diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..ff261ba --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,9 @@ +ARG VARIANT="3.9" +FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} + +USER vscode + +RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash +ENV PATH=/home/vscode/.rye/shims:$PATH + +RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..c17fdc1 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,43 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "Debian", + "build": { + "dockerfile": "Dockerfile", + "context": ".." + }, + + "postStartCommand": "rye sync --all-features", + + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python" + ], + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "python.pythonPath": ".venv/bin/python", + "python.defaultInterpreterPath": ".venv/bin/python", + "python.typeChecking": "basic", + "terminal.integrated.env.linux": { + "PATH": "/home/vscode/.rye/shims:${env:PATH}" + } + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": {} + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..322b0f7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,96 @@ +name: CI +on: + push: + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' + +jobs: + lint: + timeout-minutes: 10 + name: lint + 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 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run lints + run: ./scripts/lint + + build: + if: github.repository == 'stainless-sdks/gitpod-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) + timeout-minutes: 10 + name: build + permissions: + contents: read + id-token: write + runs-on: depot-ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run build + run: rye build + + - name: Get GitHub OIDC Token + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Upload tarball + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh + + test: + timeout-minutes: 10 + name: test + 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 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Run tests + run: ./scripts/test diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml new file mode 100644 index 0000000..6cd33a6 --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,31 @@ +# This workflow is triggered when a GitHub release is created. +# It can also be run manually to re-publish to PyPI in case it failed for some reason. +# You can run this workflow by navigating to https://www.github.com/gitpod-io/gitpod-sdk-python/actions/workflows/publish-pypi.yml +name: Publish PyPI +on: + workflow_dispatch: + + release: + types: [published] + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Publish to PyPI + run: | + bash ./bin/publish-pypi + env: + PYPI_TOKEN: ${{ secrets.GITPOD_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 0000000..f7fa281 --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,21 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'gitpod-io/gitpod-sdk-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + PYPI_TOKEN: ${{ secrets.GITPOD_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8779740 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.prism.log +.vscode +_dev + +__pycache__ +.mypy_cache + +dist + +.venv +.idea + +.env +.envrc +codegen.log +Brewfile.lock.json diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..43077b2 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.9.18 diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..6b7b74c --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.3.0" +} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml new file mode 100644 index 0000000..d375176 --- /dev/null +++ b/.stats.yml @@ -0,0 +1,4 @@ +configured_endpoints: 119 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-ca9a49ac7fbb63f55611fd7cd48a22a3ff8b38a797125c8513e891d9b7345550.yml +openapi_spec_hash: fd6ffbdfaefcc555e61ca1c565e05214 +config_hash: bb9d0a0bdadbee0985dd7c1e4f0e9e8a diff --git a/Brewfile b/Brewfile new file mode 100644 index 0000000..492ca37 --- /dev/null +++ b/Brewfile @@ -0,0 +1,2 @@ +brew "rye" + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8e1d17a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,128 @@ +## Setting up the environment + +### With Rye + +We use [Rye](https://rye.astral.sh/) to manage dependencies because it will automatically provision a Python environment with the expected Python version. To set it up, run: + +```sh +$ ./scripts/bootstrap +``` + +Or [install Rye manually](https://rye.astral.sh/guide/installation/) and run: + +```sh +$ rye sync --all-features +``` + +You can then run scripts using `rye run python script.py` or by activating the virtual environment: + +```sh +# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work +$ source .venv/bin/activate + +# now you can omit the `rye run` prefix +$ python script.py +``` + +### Without Rye + +Alternatively if you don't want to install `Rye`, you can stick with the standard `pip` setup by ensuring you have the Python version specified in `.python-version`, create a virtual environment however you desire and then install dependencies using this command: + +```sh +$ pip install -r requirements-dev.lock +``` + +## Modifying/Adding code + +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may +result in merge conflicts between manual patches and changes from the generator. The generator will never +modify the contents of the `src/gitpod/lib/` and `examples/` directories. + +## Adding and running examples + +All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. + +```py +# add an example to examples/<your-example>.py + +#!/usr/bin/env -S rye run python +… +``` + +```sh +$ chmod +x examples/<your-example>.py +# run the example against your api +$ ./examples/<your-example>.py +``` + +## Using the repository from source + +If you’d like to use the repository from source, you can either install from git or link to a cloned repository: + +To install via git: + +```sh +$ pip install git+ssh://git@github.com/gitpod-io/gitpod-sdk-python.git +``` + +Alternatively, you can build from source and install the wheel file: + +Building this package will create two files in the `dist/` directory, a `.tar.gz` containing the source files and a `.whl` that can be used to install the package efficiently. + +To create a distributable version of the library, all you have to do is run this command: + +```sh +$ rye build +# or +$ python -m build +``` + +Then to install: + +```sh +$ pip install ./path-to-wheel-file.whl +``` + +## Running tests + +Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. + +```sh +# you will need npm installed +$ npx prism mock path/to/your/openapi.yml +``` + +```sh +$ ./scripts/test +``` + +## Linting and formatting + +This repository uses [ruff](https://github.com/astral-sh/ruff) and +[black](https://github.com/psf/black) to format the code in the repository. + +To lint: + +```sh +$ ./scripts/lint +``` + +To format and fix all ruff issues automatically: + +```sh +$ ./scripts/format +``` + +## Publishing and releases + +Changes made to this repository via the automated release PR pipeline should publish to PyPI automatically. If +the changes aren't made through the automated pipeline, you may want to make releases manually. + +### Publish with a GitHub workflow + +You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/gitpod-io/gitpod-sdk-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up. + +### Publish manually + +If you need to manually release a package, you can run the `bin/publish-pypi` script with a `PYPI_TOKEN` set on +the environment. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..01fd4f2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Gitpod + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index c2b730a..b5d5626 100644 --- a/README.md +++ b/README.md @@ -1 +1,441 @@ -# gitpod-python \ No newline at end of file +# Gitpod Python API library + +<!-- prettier-ignore --> +[)](https://pypi.org/project/gitpod-sdk/) + +The Gitpod Python library provides convenient access to the Gitpod REST API from any Python 3.8+ +application. The library includes type definitions for all request params and response fields, +and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). + +It is generated with [Stainless](https://www.stainless.com/). + +## Documentation + +The REST API documentation can be found on [docs.gitpod.io](https://docs.gitpod.io). The full API of this library can be found in [api.md](api.md). + +## Installation + +```sh +# install from PyPI +pip install gitpod-sdk +``` + +## Usage + +The full API of this library can be found in [api.md](api.md). + +```python +import os +from gitpod import Gitpod + +client = Gitpod( + bearer_token=os.environ.get("GITPOD_API_KEY"), # This is the default and can be omitted +) + +response = client.identity.get_authenticated_identity() +print(response.organization_id) +``` + +While you can provide a `bearer_token` keyword argument, +we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) +to add `GITPOD_API_KEY="My Bearer Token"` to your `.env` file +so that your Bearer Token is not stored in source control. + +## Async usage + +Simply import `AsyncGitpod` instead of `Gitpod` and use `await` with each API call: + +```python +import os +import asyncio +from gitpod import AsyncGitpod + +client = AsyncGitpod( + bearer_token=os.environ.get("GITPOD_API_KEY"), # This is the default and can be omitted +) + + +async def main() -> None: + response = await client.identity.get_authenticated_identity() + print(response.organization_id) + + +asyncio.run(main()) +``` + +Functionality between the synchronous and asynchronous clients is otherwise identical. + +### With aiohttp + +By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. + +You can enable this by installing `aiohttp`: + +```sh +# install from PyPI +pip install gitpod-sdk[aiohttp] +``` + +Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: + +```python +import asyncio +from gitpod import DefaultAioHttpClient +from gitpod import AsyncGitpod + + +async def main() -> None: + async with AsyncGitpod( + bearer_token="My Bearer Token", + http_client=DefaultAioHttpClient(), + ) as client: + response = await client.identity.get_authenticated_identity() + print(response.organization_id) + + +asyncio.run(main()) +``` + +## Using types + +Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: + +- Serializing back into JSON, `model.to_json()` +- Converting to a dictionary, `model.to_dict()` + +Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. + +## Pagination + +List methods in the Gitpod API are paginated. + +This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually: + +```python +from gitpod import Gitpod + +client = Gitpod() + +all_environments = [] +# Automatically fetches more pages as needed. +for environment in client.environments.list(): + # Do something with environment here + all_environments.append(environment) +print(all_environments) +``` + +Or, asynchronously: + +```python +import asyncio +from gitpod import AsyncGitpod + +client = AsyncGitpod() + + +async def main() -> None: + all_environments = [] + # Iterate through items across all pages, issuing requests as needed. + async for environment in client.environments.list(): + all_environments.append(environment) + print(all_environments) + + +asyncio.run(main()) +``` + +Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages: + +```python +first_page = await client.environments.list() +if first_page.has_next_page(): + print(f"will fetch next page using these details: {first_page.next_page_info()}") + next_page = await first_page.get_next_page() + print(f"number of items we just fetched: {len(next_page.environments)}") + +# Remove `await` for non-async usage. +``` + +Or just work directly with the returned data: + +```python +first_page = await client.environments.list() + +print(f"next page cursor: {first_page.pagination.next_token}") # => "next page cursor: ..." +for environment in first_page.environments: + print(environment.id) + +# Remove `await` for non-async usage. +``` + +## Nested params + +Nested parameters are dictionaries, typed using `TypedDict`, for example: + +```python +from gitpod import Gitpod + +client = Gitpod() + +page = client.accounts.list_login_providers( + filter={}, +) +print(page.login_providers) +``` + +## Handling errors + +When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `gitpod.APIConnectionError` is raised. + +When the API returns a non-success status code (that is, 4xx or 5xx +response), a subclass of `gitpod.APIStatusError` is raised, containing `status_code` and `response` properties. + +All errors inherit from `gitpod.APIError`. + +```python +import gitpod +from gitpod import Gitpod + +client = Gitpod() + +try: + client.identity.get_authenticated_identity() +except gitpod.APIConnectionError as e: + print("The server could not be reached") + print(e.__cause__) # an underlying Exception, likely raised within httpx. +except gitpod.RateLimitError as e: + print("A 429 status code was received; we should back off a bit.") +except gitpod.APIStatusError as e: + print("Another non-200-range status code was received") + print(e.status_code) + print(e.response) +``` + +Error codes are as follows: + +| Status Code | Error Type | +| ----------- | -------------------------- | +| 400 | `BadRequestError` | +| 401 | `AuthenticationError` | +| 403 | `PermissionDeniedError` | +| 404 | `NotFoundError` | +| 422 | `UnprocessableEntityError` | +| 429 | `RateLimitError` | +| >=500 | `InternalServerError` | +| N/A | `APIConnectionError` | + +### Retries + +Certain errors are automatically retried 2 times by default, with a short exponential backoff. +Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, +429 Rate Limit, and >=500 Internal errors are all retried by default. + +You can use the `max_retries` option to configure or disable retry settings: + +```python +from gitpod import Gitpod + +# Configure the default for all requests: +client = Gitpod( + # default is 2 + max_retries=0, +) + +# Or, configure per-request: +client.with_options(max_retries=5).identity.get_authenticated_identity() +``` + +### Timeouts + +By default requests time out after 1 minute. You can configure this with a `timeout` option, +which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: + +```python +from gitpod import Gitpod + +# Configure the default for all requests: +client = Gitpod( + # 20 seconds (default is 1 minute) + timeout=20.0, +) + +# More granular control: +client = Gitpod( + timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0), +) + +# Override per-request: +client.with_options(timeout=5.0).identity.get_authenticated_identity() +``` + +On timeout, an `APITimeoutError` is thrown. + +Note that requests that time out are [retried twice by default](#retries). + +## Advanced + +### Logging + +We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. + +You can enable logging by setting the environment variable `GITPOD_LOG` to `info`. + +```shell +$ export GITPOD_LOG=info +``` + +Or to `debug` for more verbose logging. + +### How to tell whether `None` means `null` or missing + +In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: + +```py +if response.my_field is None: + if 'my_field' not in response.model_fields_set: + print('Got json like {}, without a "my_field" key present at all.') + else: + print('Got json like {"my_field": null}.') +``` + +### Accessing raw response data (e.g. headers) + +The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g., + +```py +from gitpod import Gitpod + +client = Gitpod() +response = client.identity.with_raw_response.get_authenticated_identity() +print(response.headers.get('X-My-Header')) + +identity = response.parse() # get the object that `identity.get_authenticated_identity()` would have returned +print(identity.organization_id) +``` + +These methods return an [`APIResponse`](https://github.com/gitpod-io/gitpod-sdk-python/tree/main/src/gitpod/_response.py) object. + +The async client returns an [`AsyncAPIResponse`](https://github.com/gitpod-io/gitpod-sdk-python/tree/main/src/gitpod/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. + +#### `.with_streaming_response` + +The above interface eagerly reads the full response body when you make the request, which may not always be what you want. + +To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. + +```python +with client.identity.with_streaming_response.get_authenticated_identity() as response: + print(response.headers.get("X-My-Header")) + + for line in response.iter_lines(): + print(line) +``` + +The context manager is required so that the response will reliably be closed. + +### Making custom/undocumented requests + +This library is typed for convenient access to the documented API. + +If you need to access undocumented endpoints, params, or response properties, the library can still be used. + +#### Undocumented endpoints + +To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other +http verbs. Options on the client will be respected (such as retries) when making this request. + +```py +import httpx + +response = client.post( + "/foo", + cast_to=httpx.Response, + body={"my_param": True}, +) + +print(response.headers.get("x-foo")) +``` + +#### Undocumented request params + +If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request +options. + +#### Undocumented response properties + +To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You +can also get all the extra fields on the Pydantic model as a dict with +[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra). + +### Configuring the HTTP client + +You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including: + +- Support for [proxies](https://www.python-httpx.org/advanced/proxies/) +- Custom [transports](https://www.python-httpx.org/advanced/transports/) +- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality + +```python +import httpx +from gitpod import Gitpod, DefaultHttpxClient + +client = Gitpod( + # Or use the `GITPOD_BASE_URL` env var + base_url="http://my.test.server.example.com:8083", + http_client=DefaultHttpxClient( + proxy="http://my.test.proxy.example.com", + transport=httpx.HTTPTransport(local_address="0.0.0.0"), + ), +) +``` + +You can also customize the client on a per-request basis by using `with_options()`: + +```python +client.with_options(http_client=DefaultHttpxClient(...)) +``` + +### Managing HTTP resources + +By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. + +```py +from gitpod import Gitpod + +with Gitpod() as client: + # make requests here + ... + +# HTTP client is now closed +``` + +## Versioning + +This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: + +1. Changes that only affect static types, without breaking runtime behavior. +2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ +3. Changes that we do not expect to impact the vast majority of users in practice. + +We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. + +We are keen for your feedback; please open an [issue](https://www.github.com/gitpod-io/gitpod-sdk-python/issues) with questions, bugs, or suggestions. + +### Determining the installed version + +If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. + +You can determine the version that is being used at runtime with: + +```py +import gitpod +print(gitpod.__version__) +``` + +## Requirements + +Python 3.8 or higher. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..efd9088 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Reporting Security Issues + +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. + +To report a security issue, please contact the Stainless team at security@stainless.com. + +## Responsible Disclosure + +We appreciate the efforts of security researchers and individuals who help us maintain the security of +SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible +disclosure practices by allowing us a reasonable amount of time to investigate and address the issue +before making any information public. + +## Reporting Non-SDK Related Security Issues + +If you encounter security issues that are not directly related to SDKs but pertain to the services +or products provided by Gitpod, please follow the respective company's security reporting guidelines. + +### Gitpod Terms and Policies + +Please contact dev-feedback@gitpod.com for any questions or concerns regarding the security of our services. + +--- + +Thank you for helping us keep the SDKs and systems they interact with secure. diff --git a/api.md b/api.md new file mode 100644 index 0000000..d6b34b7 --- /dev/null +++ b/api.md @@ -0,0 +1,591 @@ +# Shared Types + +```python +from gitpod.types import ( + AutomationTrigger, + EnvironmentClass, + ErrorCode, + FieldValue, + Gateway, + OrganizationRole, + Principal, + RunsOn, + Subject, + Task, + TaskExecution, + TaskExecutionMetadata, + TaskExecutionPhase, + TaskExecutionSpec, + TaskExecutionStatus, + TaskMetadata, + TaskSpec, + UserStatus, +) +``` + +# Accounts + +Types: + +```python +from gitpod.types import ( + Account, + AccountMembership, + JoinableOrganization, + LoginProvider, + AccountRetrieveResponse, + AccountGetSSOLoginURLResponse, + AccountListJoinableOrganizationsResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.AccountService/GetAccount">client.accounts.<a href="./src/gitpod/resources/accounts.py">retrieve</a>(\*\*<a href="src/gitpod/types/account_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/account_retrieve_response.py">AccountRetrieveResponse</a></code> +- <code title="post /gitpod.v1.AccountService/DeleteAccount">client.accounts.<a href="./src/gitpod/resources/accounts.py">delete</a>(\*\*<a href="src/gitpod/types/account_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.AccountService/GetSSOLoginURL">client.accounts.<a href="./src/gitpod/resources/accounts.py">get_sso_login_url</a>(\*\*<a href="src/gitpod/types/account_get_sso_login_url_params.py">params</a>) -> <a href="./src/gitpod/types/account_get_sso_login_url_response.py">AccountGetSSOLoginURLResponse</a></code> +- <code title="post /gitpod.v1.AccountService/ListJoinableOrganizations">client.accounts.<a href="./src/gitpod/resources/accounts.py">list_joinable_organizations</a>(\*\*<a href="src/gitpod/types/account_list_joinable_organizations_params.py">params</a>) -> <a href="./src/gitpod/types/account_list_joinable_organizations_response.py">AccountListJoinableOrganizationsResponse</a></code> +- <code title="post /gitpod.v1.AccountService/ListLoginProviders">client.accounts.<a href="./src/gitpod/resources/accounts.py">list_login_providers</a>(\*\*<a href="src/gitpod/types/account_list_login_providers_params.py">params</a>) -> <a href="./src/gitpod/types/login_provider.py">SyncLoginProvidersPage[LoginProvider]</a></code> + +# Editors + +Types: + +```python +from gitpod.types import Editor, EditorRetrieveResponse, EditorResolveURLResponse +``` + +Methods: + +- <code title="post /gitpod.v1.EditorService/GetEditor">client.editors.<a href="./src/gitpod/resources/editors.py">retrieve</a>(\*\*<a href="src/gitpod/types/editor_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/editor_retrieve_response.py">EditorRetrieveResponse</a></code> +- <code title="post /gitpod.v1.EditorService/ListEditors">client.editors.<a href="./src/gitpod/resources/editors.py">list</a>(\*\*<a href="src/gitpod/types/editor_list_params.py">params</a>) -> <a href="./src/gitpod/types/editor.py">SyncEditorsPage[Editor]</a></code> +- <code title="post /gitpod.v1.EditorService/ResolveEditorURL">client.editors.<a href="./src/gitpod/resources/editors.py">resolve_url</a>(\*\*<a href="src/gitpod/types/editor_resolve_url_params.py">params</a>) -> <a href="./src/gitpod/types/editor_resolve_url_response.py">EditorResolveURLResponse</a></code> + +# Environments + +Types: + +```python +from gitpod.types import ( + AdmissionLevel, + Environment, + EnvironmentActivitySignal, + EnvironmentMetadata, + EnvironmentPhase, + EnvironmentSpec, + EnvironmentStatus, + EnvironmentCreateResponse, + EnvironmentRetrieveResponse, + EnvironmentCreateEnvironmentTokenResponse, + EnvironmentCreateFromProjectResponse, + EnvironmentCreateLogsTokenResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.EnvironmentService/CreateEnvironment">client.environments.<a href="./src/gitpod/resources/environments/environments.py">create</a>(\*\*<a href="src/gitpod/types/environment_create_params.py">params</a>) -> <a href="./src/gitpod/types/environment_create_response.py">EnvironmentCreateResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentService/GetEnvironment">client.environments.<a href="./src/gitpod/resources/environments/environments.py">retrieve</a>(\*\*<a href="src/gitpod/types/environment_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/environment_retrieve_response.py">EnvironmentRetrieveResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentService/UpdateEnvironment">client.environments.<a href="./src/gitpod/resources/environments/environments.py">update</a>(\*\*<a href="src/gitpod/types/environment_update_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentService/ListEnvironments">client.environments.<a href="./src/gitpod/resources/environments/environments.py">list</a>(\*\*<a href="src/gitpod/types/environment_list_params.py">params</a>) -> <a href="./src/gitpod/types/environment.py">SyncEnvironmentsPage[Environment]</a></code> +- <code title="post /gitpod.v1.EnvironmentService/DeleteEnvironment">client.environments.<a href="./src/gitpod/resources/environments/environments.py">delete</a>(\*\*<a href="src/gitpod/types/environment_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentService/CreateEnvironmentAccessToken">client.environments.<a href="./src/gitpod/resources/environments/environments.py">create_environment_token</a>(\*\*<a href="src/gitpod/types/environment_create_environment_token_params.py">params</a>) -> <a href="./src/gitpod/types/environment_create_environment_token_response.py">EnvironmentCreateEnvironmentTokenResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentService/CreateEnvironmentFromProject">client.environments.<a href="./src/gitpod/resources/environments/environments.py">create_from_project</a>(\*\*<a href="src/gitpod/types/environment_create_from_project_params.py">params</a>) -> <a href="./src/gitpod/types/environment_create_from_project_response.py">EnvironmentCreateFromProjectResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentService/CreateEnvironmentLogsToken">client.environments.<a href="./src/gitpod/resources/environments/environments.py">create_logs_token</a>(\*\*<a href="src/gitpod/types/environment_create_logs_token_params.py">params</a>) -> <a href="./src/gitpod/types/environment_create_logs_token_response.py">EnvironmentCreateLogsTokenResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentService/MarkEnvironmentActive">client.environments.<a href="./src/gitpod/resources/environments/environments.py">mark_active</a>(\*\*<a href="src/gitpod/types/environment_mark_active_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentService/StartEnvironment">client.environments.<a href="./src/gitpod/resources/environments/environments.py">start</a>(\*\*<a href="src/gitpod/types/environment_start_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentService/StopEnvironment">client.environments.<a href="./src/gitpod/resources/environments/environments.py">stop</a>(\*\*<a href="src/gitpod/types/environment_stop_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentService/UnarchiveEnvironment">client.environments.<a href="./src/gitpod/resources/environments/environments.py">unarchive</a>(\*\*<a href="src/gitpod/types/environment_unarchive_params.py">params</a>) -> object</code> + +## Automations + +Types: + +```python +from gitpod.types.environments import AutomationsFile, AutomationUpsertResponse +``` + +Methods: + +- <code title="post /gitpod.v1.EnvironmentAutomationService/UpsertAutomationsFile">client.environments.automations.<a href="./src/gitpod/resources/environments/automations/automations.py">upsert</a>(\*\*<a href="src/gitpod/types/environments/automation_upsert_params.py">params</a>) -> <a href="./src/gitpod/types/environments/automation_upsert_response.py">AutomationUpsertResponse</a></code> + +### Services + +Types: + +```python +from gitpod.types.environments.automations import ( + Service, + ServiceMetadata, + ServicePhase, + ServiceSpec, + ServiceStatus, + ServiceCreateResponse, + ServiceRetrieveResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.EnvironmentAutomationService/CreateService">client.environments.automations.services.<a href="./src/gitpod/resources/environments/automations/services.py">create</a>(\*\*<a href="src/gitpod/types/environments/automations/service_create_params.py">params</a>) -> <a href="./src/gitpod/types/environments/automations/service_create_response.py">ServiceCreateResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/GetService">client.environments.automations.services.<a href="./src/gitpod/resources/environments/automations/services.py">retrieve</a>(\*\*<a href="src/gitpod/types/environments/automations/service_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/environments/automations/service_retrieve_response.py">ServiceRetrieveResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/UpdateService">client.environments.automations.services.<a href="./src/gitpod/resources/environments/automations/services.py">update</a>(\*\*<a href="src/gitpod/types/environments/automations/service_update_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/ListServices">client.environments.automations.services.<a href="./src/gitpod/resources/environments/automations/services.py">list</a>(\*\*<a href="src/gitpod/types/environments/automations/service_list_params.py">params</a>) -> <a href="./src/gitpod/types/environments/automations/service.py">SyncServicesPage[Service]</a></code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/DeleteService">client.environments.automations.services.<a href="./src/gitpod/resources/environments/automations/services.py">delete</a>(\*\*<a href="src/gitpod/types/environments/automations/service_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/StartService">client.environments.automations.services.<a href="./src/gitpod/resources/environments/automations/services.py">start</a>(\*\*<a href="src/gitpod/types/environments/automations/service_start_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/StopService">client.environments.automations.services.<a href="./src/gitpod/resources/environments/automations/services.py">stop</a>(\*\*<a href="src/gitpod/types/environments/automations/service_stop_params.py">params</a>) -> object</code> + +### Tasks + +Types: + +```python +from gitpod.types.environments.automations import ( + TaskCreateResponse, + TaskRetrieveResponse, + TaskStartResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.EnvironmentAutomationService/CreateTask">client.environments.automations.tasks.<a href="./src/gitpod/resources/environments/automations/tasks/tasks.py">create</a>(\*\*<a href="src/gitpod/types/environments/automations/task_create_params.py">params</a>) -> <a href="./src/gitpod/types/environments/automations/task_create_response.py">TaskCreateResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/GetTask">client.environments.automations.tasks.<a href="./src/gitpod/resources/environments/automations/tasks/tasks.py">retrieve</a>(\*\*<a href="src/gitpod/types/environments/automations/task_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/environments/automations/task_retrieve_response.py">TaskRetrieveResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/UpdateTask">client.environments.automations.tasks.<a href="./src/gitpod/resources/environments/automations/tasks/tasks.py">update</a>(\*\*<a href="src/gitpod/types/environments/automations/task_update_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/ListTasks">client.environments.automations.tasks.<a href="./src/gitpod/resources/environments/automations/tasks/tasks.py">list</a>(\*\*<a href="src/gitpod/types/environments/automations/task_list_params.py">params</a>) -> <a href="./src/gitpod/types/shared/task.py">SyncTasksPage[Task]</a></code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/DeleteTask">client.environments.automations.tasks.<a href="./src/gitpod/resources/environments/automations/tasks/tasks.py">delete</a>(\*\*<a href="src/gitpod/types/environments/automations/task_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/StartTask">client.environments.automations.tasks.<a href="./src/gitpod/resources/environments/automations/tasks/tasks.py">start</a>(\*\*<a href="src/gitpod/types/environments/automations/task_start_params.py">params</a>) -> <a href="./src/gitpod/types/environments/automations/task_start_response.py">TaskStartResponse</a></code> + +#### Executions + +Types: + +```python +from gitpod.types.environments.automations.tasks import ExecutionRetrieveResponse +``` + +Methods: + +- <code title="post /gitpod.v1.EnvironmentAutomationService/GetTaskExecution">client.environments.automations.tasks.executions.<a href="./src/gitpod/resources/environments/automations/tasks/executions.py">retrieve</a>(\*\*<a href="src/gitpod/types/environments/automations/tasks/execution_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/environments/automations/tasks/execution_retrieve_response.py">ExecutionRetrieveResponse</a></code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/ListTaskExecutions">client.environments.automations.tasks.executions.<a href="./src/gitpod/resources/environments/automations/tasks/executions.py">list</a>(\*\*<a href="src/gitpod/types/environments/automations/tasks/execution_list_params.py">params</a>) -> <a href="./src/gitpod/types/shared/task_execution.py">SyncTaskExecutionsPage[TaskExecution]</a></code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/StopTaskExecution">client.environments.automations.tasks.executions.<a href="./src/gitpod/resources/environments/automations/tasks/executions.py">stop</a>(\*\*<a href="src/gitpod/types/environments/automations/tasks/execution_stop_params.py">params</a>) -> object</code> + +## Classes + +Methods: + +- <code title="post /gitpod.v1.EnvironmentService/ListEnvironmentClasses">client.environments.classes.<a href="./src/gitpod/resources/environments/classes.py">list</a>(\*\*<a href="src/gitpod/types/environments/class_list_params.py">params</a>) -> <a href="./src/gitpod/types/shared/environment_class.py">SyncEnvironmentClassesPage[EnvironmentClass]</a></code> + +# Events + +Types: + +```python +from gitpod.types import ResourceOperation, ResourceType, EventListResponse, EventWatchResponse +``` + +Methods: + +- <code title="post /gitpod.v1.EventService/ListAuditLogs">client.events.<a href="./src/gitpod/resources/events.py">list</a>(\*\*<a href="src/gitpod/types/event_list_params.py">params</a>) -> <a href="./src/gitpod/types/event_list_response.py">SyncEntriesPage[EventListResponse]</a></code> +- <code title="post /gitpod.v1.EventService/WatchEvents">client.events.<a href="./src/gitpod/resources/events.py">watch</a>(\*\*<a href="src/gitpod/types/event_watch_params.py">params</a>) -> <a href="./src/gitpod/types/event_watch_response.py">JSONLDecoder[EventWatchResponse]</a></code> + +# Gateways + +Methods: + +- <code title="post /gitpod.v1.GatewayService/ListGateways">client.gateways.<a href="./src/gitpod/resources/gateways.py">list</a>(\*\*<a href="src/gitpod/types/gateway_list_params.py">params</a>) -> <a href="./src/gitpod/types/shared/gateway.py">SyncGatewaysPage[Gateway]</a></code> + +# Groups + +Types: + +```python +from gitpod.types import Group +``` + +Methods: + +- <code title="post /gitpod.v1.GroupService/ListGroups">client.groups.<a href="./src/gitpod/resources/groups.py">list</a>(\*\*<a href="src/gitpod/types/group_list_params.py">params</a>) -> <a href="./src/gitpod/types/group.py">SyncGroupsPage[Group]</a></code> + +# Identity + +Types: + +```python +from gitpod.types import ( + IDTokenVersion, + IdentityExchangeTokenResponse, + IdentityGetAuthenticatedIdentityResponse, + IdentityGetIDTokenResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.IdentityService/ExchangeToken">client.identity.<a href="./src/gitpod/resources/identity.py">exchange_token</a>(\*\*<a href="src/gitpod/types/identity_exchange_token_params.py">params</a>) -> <a href="./src/gitpod/types/identity_exchange_token_response.py">IdentityExchangeTokenResponse</a></code> +- <code title="post /gitpod.v1.IdentityService/GetAuthenticatedIdentity">client.identity.<a href="./src/gitpod/resources/identity.py">get_authenticated_identity</a>(\*\*<a href="src/gitpod/types/identity_get_authenticated_identity_params.py">params</a>) -> <a href="./src/gitpod/types/identity_get_authenticated_identity_response.py">IdentityGetAuthenticatedIdentityResponse</a></code> +- <code title="post /gitpod.v1.IdentityService/GetIDToken">client.identity.<a href="./src/gitpod/resources/identity.py">get_id_token</a>(\*\*<a href="src/gitpod/types/identity_get_id_token_params.py">params</a>) -> <a href="./src/gitpod/types/identity_get_id_token_response.py">IdentityGetIDTokenResponse</a></code> + +# Organizations + +Types: + +```python +from gitpod.types import ( + InviteDomains, + Organization, + OrganizationMember, + OrganizationTier, + OrganizationCreateResponse, + OrganizationRetrieveResponse, + OrganizationUpdateResponse, + OrganizationJoinResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/CreateOrganization">client.organizations.<a href="./src/gitpod/resources/organizations/organizations.py">create</a>(\*\*<a href="src/gitpod/types/organization_create_params.py">params</a>) -> <a href="./src/gitpod/types/organization_create_response.py">OrganizationCreateResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/GetOrganization">client.organizations.<a href="./src/gitpod/resources/organizations/organizations.py">retrieve</a>(\*\*<a href="src/gitpod/types/organization_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/organization_retrieve_response.py">OrganizationRetrieveResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/UpdateOrganization">client.organizations.<a href="./src/gitpod/resources/organizations/organizations.py">update</a>(\*\*<a href="src/gitpod/types/organization_update_params.py">params</a>) -> <a href="./src/gitpod/types/organization_update_response.py">OrganizationUpdateResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/DeleteOrganization">client.organizations.<a href="./src/gitpod/resources/organizations/organizations.py">delete</a>(\*\*<a href="src/gitpod/types/organization_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.OrganizationService/JoinOrganization">client.organizations.<a href="./src/gitpod/resources/organizations/organizations.py">join</a>(\*\*<a href="src/gitpod/types/organization_join_params.py">params</a>) -> <a href="./src/gitpod/types/organization_join_response.py">OrganizationJoinResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/LeaveOrganization">client.organizations.<a href="./src/gitpod/resources/organizations/organizations.py">leave</a>(\*\*<a href="src/gitpod/types/organization_leave_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.OrganizationService/ListMembers">client.organizations.<a href="./src/gitpod/resources/organizations/organizations.py">list_members</a>(\*\*<a href="src/gitpod/types/organization_list_members_params.py">params</a>) -> <a href="./src/gitpod/types/organization_member.py">SyncMembersPage[OrganizationMember]</a></code> +- <code title="post /gitpod.v1.OrganizationService/SetRole">client.organizations.<a href="./src/gitpod/resources/organizations/organizations.py">set_role</a>(\*\*<a href="src/gitpod/types/organization_set_role_params.py">params</a>) -> object</code> + +## DomainVerifications + +Types: + +```python +from gitpod.types.organizations import ( + DomainVerification, + DomainVerificationState, + DomainVerificationCreateResponse, + DomainVerificationRetrieveResponse, + DomainVerificationVerifyResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/CreateDomainVerification">client.organizations.domain_verifications.<a href="./src/gitpod/resources/organizations/domain_verifications.py">create</a>(\*\*<a href="src/gitpod/types/organizations/domain_verification_create_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/domain_verification_create_response.py">DomainVerificationCreateResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/GetDomainVerification">client.organizations.domain_verifications.<a href="./src/gitpod/resources/organizations/domain_verifications.py">retrieve</a>(\*\*<a href="src/gitpod/types/organizations/domain_verification_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/domain_verification_retrieve_response.py">DomainVerificationRetrieveResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/ListDomainVerifications">client.organizations.domain_verifications.<a href="./src/gitpod/resources/organizations/domain_verifications.py">list</a>(\*\*<a href="src/gitpod/types/organizations/domain_verification_list_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/domain_verification.py">SyncDomainVerificationsPage[DomainVerification]</a></code> +- <code title="post /gitpod.v1.OrganizationService/DeleteDomainVerification">client.organizations.domain_verifications.<a href="./src/gitpod/resources/organizations/domain_verifications.py">delete</a>(\*\*<a href="src/gitpod/types/organizations/domain_verification_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.OrganizationService/VerifyDomain">client.organizations.domain_verifications.<a href="./src/gitpod/resources/organizations/domain_verifications.py">verify</a>(\*\*<a href="src/gitpod/types/organizations/domain_verification_verify_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/domain_verification_verify_response.py">DomainVerificationVerifyResponse</a></code> + +## Invites + +Types: + +```python +from gitpod.types.organizations import ( + OrganizationInvite, + InviteCreateResponse, + InviteRetrieveResponse, + InviteGetSummaryResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/CreateOrganizationInvite">client.organizations.invites.<a href="./src/gitpod/resources/organizations/invites.py">create</a>(\*\*<a href="src/gitpod/types/organizations/invite_create_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/invite_create_response.py">InviteCreateResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/GetOrganizationInvite">client.organizations.invites.<a href="./src/gitpod/resources/organizations/invites.py">retrieve</a>(\*\*<a href="src/gitpod/types/organizations/invite_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/invite_retrieve_response.py">InviteRetrieveResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/GetOrganizationInviteSummary">client.organizations.invites.<a href="./src/gitpod/resources/organizations/invites.py">get_summary</a>(\*\*<a href="src/gitpod/types/organizations/invite_get_summary_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/invite_get_summary_response.py">InviteGetSummaryResponse</a></code> + +## Policies + +Types: + +```python +from gitpod.types.organizations import OrganizationPolicies, PolicyRetrieveResponse +``` + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/GetOrganizationPolicies">client.organizations.policies.<a href="./src/gitpod/resources/organizations/policies.py">retrieve</a>(\*\*<a href="src/gitpod/types/organizations/policy_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/policy_retrieve_response.py">PolicyRetrieveResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/UpdateOrganizationPolicies">client.organizations.policies.<a href="./src/gitpod/resources/organizations/policies.py">update</a>(\*\*<a href="src/gitpod/types/organizations/policy_update_params.py">params</a>) -> object</code> + +## SSOConfigurations + +Types: + +```python +from gitpod.types.organizations import ( + ProviderType, + SSOConfiguration, + SSOConfigurationState, + SSOConfigurationCreateResponse, + SSOConfigurationRetrieveResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/CreateSSOConfiguration">client.organizations.sso_configurations.<a href="./src/gitpod/resources/organizations/sso_configurations.py">create</a>(\*\*<a href="src/gitpod/types/organizations/sso_configuration_create_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/sso_configuration_create_response.py">SSOConfigurationCreateResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/GetSSOConfiguration">client.organizations.sso_configurations.<a href="./src/gitpod/resources/organizations/sso_configurations.py">retrieve</a>(\*\*<a href="src/gitpod/types/organizations/sso_configuration_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/sso_configuration_retrieve_response.py">SSOConfigurationRetrieveResponse</a></code> +- <code title="post /gitpod.v1.OrganizationService/UpdateSSOConfiguration">client.organizations.sso_configurations.<a href="./src/gitpod/resources/organizations/sso_configurations.py">update</a>(\*\*<a href="src/gitpod/types/organizations/sso_configuration_update_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.OrganizationService/ListSSOConfigurations">client.organizations.sso_configurations.<a href="./src/gitpod/resources/organizations/sso_configurations.py">list</a>(\*\*<a href="src/gitpod/types/organizations/sso_configuration_list_params.py">params</a>) -> <a href="./src/gitpod/types/organizations/sso_configuration.py">SyncSSOConfigurationsPage[SSOConfiguration]</a></code> +- <code title="post /gitpod.v1.OrganizationService/DeleteSSOConfiguration">client.organizations.sso_configurations.<a href="./src/gitpod/resources/organizations/sso_configurations.py">delete</a>(\*\*<a href="src/gitpod/types/organizations/sso_configuration_delete_params.py">params</a>) -> object</code> + +# Projects + +Types: + +```python +from gitpod.types import ( + EnvironmentInitializer, + Project, + ProjectEnvironmentClass, + ProjectMetadata, + ProjectCreateResponse, + ProjectRetrieveResponse, + ProjectUpdateResponse, + ProjectCreateFromEnvironmentResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.ProjectService/CreateProject">client.projects.<a href="./src/gitpod/resources/projects/projects.py">create</a>(\*\*<a href="src/gitpod/types/project_create_params.py">params</a>) -> <a href="./src/gitpod/types/project_create_response.py">ProjectCreateResponse</a></code> +- <code title="post /gitpod.v1.ProjectService/GetProject">client.projects.<a href="./src/gitpod/resources/projects/projects.py">retrieve</a>(\*\*<a href="src/gitpod/types/project_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/project_retrieve_response.py">ProjectRetrieveResponse</a></code> +- <code title="post /gitpod.v1.ProjectService/UpdateProject">client.projects.<a href="./src/gitpod/resources/projects/projects.py">update</a>(\*\*<a href="src/gitpod/types/project_update_params.py">params</a>) -> <a href="./src/gitpod/types/project_update_response.py">ProjectUpdateResponse</a></code> +- <code title="post /gitpod.v1.ProjectService/ListProjects">client.projects.<a href="./src/gitpod/resources/projects/projects.py">list</a>(\*\*<a href="src/gitpod/types/project_list_params.py">params</a>) -> <a href="./src/gitpod/types/project.py">SyncProjectsPage[Project]</a></code> +- <code title="post /gitpod.v1.ProjectService/DeleteProject">client.projects.<a href="./src/gitpod/resources/projects/projects.py">delete</a>(\*\*<a href="src/gitpod/types/project_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.ProjectService/CreateProjectFromEnvironment">client.projects.<a href="./src/gitpod/resources/projects/projects.py">create_from_environment</a>(\*\*<a href="src/gitpod/types/project_create_from_environment_params.py">params</a>) -> <a href="./src/gitpod/types/project_create_from_environment_response.py">ProjectCreateFromEnvironmentResponse</a></code> + +## Policies + +Types: + +```python +from gitpod.types.projects import ( + ProjectPolicy, + ProjectRole, + PolicyCreateResponse, + PolicyUpdateResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.ProjectService/CreateProjectPolicy">client.projects.policies.<a href="./src/gitpod/resources/projects/policies.py">create</a>(\*\*<a href="src/gitpod/types/projects/policy_create_params.py">params</a>) -> <a href="./src/gitpod/types/projects/policy_create_response.py">PolicyCreateResponse</a></code> +- <code title="post /gitpod.v1.ProjectService/UpdateProjectPolicy">client.projects.policies.<a href="./src/gitpod/resources/projects/policies.py">update</a>(\*\*<a href="src/gitpod/types/projects/policy_update_params.py">params</a>) -> <a href="./src/gitpod/types/projects/policy_update_response.py">PolicyUpdateResponse</a></code> +- <code title="post /gitpod.v1.ProjectService/ListProjectPolicies">client.projects.policies.<a href="./src/gitpod/resources/projects/policies.py">list</a>(\*\*<a href="src/gitpod/types/projects/policy_list_params.py">params</a>) -> <a href="./src/gitpod/types/projects/project_policy.py">SyncPoliciesPage[ProjectPolicy]</a></code> +- <code title="post /gitpod.v1.ProjectService/DeleteProjectPolicy">client.projects.policies.<a href="./src/gitpod/resources/projects/policies.py">delete</a>(\*\*<a href="src/gitpod/types/projects/policy_delete_params.py">params</a>) -> object</code> + +# Runners + +Types: + +```python +from gitpod.types import ( + GatewayInfo, + LogLevel, + MetricsConfiguration, + Runner, + RunnerCapability, + RunnerConfiguration, + RunnerKind, + RunnerPhase, + RunnerProvider, + RunnerReleaseChannel, + RunnerSpec, + RunnerStatus, + RunnerCreateResponse, + RunnerRetrieveResponse, + RunnerCheckAuthenticationForHostResponse, + RunnerCreateRunnerTokenResponse, + RunnerParseContextURLResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.RunnerService/CreateRunner">client.runners.<a href="./src/gitpod/resources/runners/runners.py">create</a>(\*\*<a href="src/gitpod/types/runner_create_params.py">params</a>) -> <a href="./src/gitpod/types/runner_create_response.py">RunnerCreateResponse</a></code> +- <code title="post /gitpod.v1.RunnerService/GetRunner">client.runners.<a href="./src/gitpod/resources/runners/runners.py">retrieve</a>(\*\*<a href="src/gitpod/types/runner_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/runner_retrieve_response.py">RunnerRetrieveResponse</a></code> +- <code title="post /gitpod.v1.RunnerService/UpdateRunner">client.runners.<a href="./src/gitpod/resources/runners/runners.py">update</a>(\*\*<a href="src/gitpod/types/runner_update_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.RunnerService/ListRunners">client.runners.<a href="./src/gitpod/resources/runners/runners.py">list</a>(\*\*<a href="src/gitpod/types/runner_list_params.py">params</a>) -> <a href="./src/gitpod/types/runner.py">SyncRunnersPage[Runner]</a></code> +- <code title="post /gitpod.v1.RunnerService/DeleteRunner">client.runners.<a href="./src/gitpod/resources/runners/runners.py">delete</a>(\*\*<a href="src/gitpod/types/runner_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.RunnerService/CheckAuthenticationForHost">client.runners.<a href="./src/gitpod/resources/runners/runners.py">check_authentication_for_host</a>(\*\*<a href="src/gitpod/types/runner_check_authentication_for_host_params.py">params</a>) -> <a href="./src/gitpod/types/runner_check_authentication_for_host_response.py">RunnerCheckAuthenticationForHostResponse</a></code> +- <code title="post /gitpod.v1.RunnerService/CreateRunnerToken">client.runners.<a href="./src/gitpod/resources/runners/runners.py">create_runner_token</a>(\*\*<a href="src/gitpod/types/runner_create_runner_token_params.py">params</a>) -> <a href="./src/gitpod/types/runner_create_runner_token_response.py">RunnerCreateRunnerTokenResponse</a></code> +- <code title="post /gitpod.v1.RunnerService/ParseContextURL">client.runners.<a href="./src/gitpod/resources/runners/runners.py">parse_context_url</a>(\*\*<a href="src/gitpod/types/runner_parse_context_url_params.py">params</a>) -> <a href="./src/gitpod/types/runner_parse_context_url_response.py">RunnerParseContextURLResponse</a></code> + +## Configurations + +Types: + +```python +from gitpod.types.runners import ( + EnvironmentClassValidationResult, + FieldValidationError, + ScmIntegrationValidationResult, + ConfigurationValidateResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/ValidateRunnerConfiguration">client.runners.configurations.<a href="./src/gitpod/resources/runners/configurations/configurations.py">validate</a>(\*\*<a href="src/gitpod/types/runners/configuration_validate_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configuration_validate_response.py">ConfigurationValidateResponse</a></code> + +### EnvironmentClasses + +Types: + +```python +from gitpod.types.runners.configurations import ( + EnvironmentClassCreateResponse, + EnvironmentClassRetrieveResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/CreateEnvironmentClass">client.runners.configurations.environment_classes.<a href="./src/gitpod/resources/runners/configurations/environment_classes.py">create</a>(\*\*<a href="src/gitpod/types/runners/configurations/environment_class_create_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/environment_class_create_response.py">EnvironmentClassCreateResponse</a></code> +- <code title="post /gitpod.v1.RunnerConfigurationService/GetEnvironmentClass">client.runners.configurations.environment_classes.<a href="./src/gitpod/resources/runners/configurations/environment_classes.py">retrieve</a>(\*\*<a href="src/gitpod/types/runners/configurations/environment_class_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/environment_class_retrieve_response.py">EnvironmentClassRetrieveResponse</a></code> +- <code title="post /gitpod.v1.RunnerConfigurationService/UpdateEnvironmentClass">client.runners.configurations.environment_classes.<a href="./src/gitpod/resources/runners/configurations/environment_classes.py">update</a>(\*\*<a href="src/gitpod/types/runners/configurations/environment_class_update_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/ListEnvironmentClasses">client.runners.configurations.environment_classes.<a href="./src/gitpod/resources/runners/configurations/environment_classes.py">list</a>(\*\*<a href="src/gitpod/types/runners/configurations/environment_class_list_params.py">params</a>) -> <a href="./src/gitpod/types/shared/environment_class.py">SyncEnvironmentClassesPage[EnvironmentClass]</a></code> + +### HostAuthenticationTokens + +Types: + +```python +from gitpod.types.runners.configurations import ( + HostAuthenticationToken, + HostAuthenticationTokenSource, + HostAuthenticationTokenCreateResponse, + HostAuthenticationTokenRetrieveResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/CreateHostAuthenticationToken">client.runners.configurations.host_authentication_tokens.<a href="./src/gitpod/resources/runners/configurations/host_authentication_tokens.py">create</a>(\*\*<a href="src/gitpod/types/runners/configurations/host_authentication_token_create_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/host_authentication_token_create_response.py">HostAuthenticationTokenCreateResponse</a></code> +- <code title="post /gitpod.v1.RunnerConfigurationService/GetHostAuthenticationToken">client.runners.configurations.host_authentication_tokens.<a href="./src/gitpod/resources/runners/configurations/host_authentication_tokens.py">retrieve</a>(\*\*<a href="src/gitpod/types/runners/configurations/host_authentication_token_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/host_authentication_token_retrieve_response.py">HostAuthenticationTokenRetrieveResponse</a></code> +- <code title="post /gitpod.v1.RunnerConfigurationService/UpdateHostAuthenticationToken">client.runners.configurations.host_authentication_tokens.<a href="./src/gitpod/resources/runners/configurations/host_authentication_tokens.py">update</a>(\*\*<a href="src/gitpod/types/runners/configurations/host_authentication_token_update_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/ListHostAuthenticationTokens">client.runners.configurations.host_authentication_tokens.<a href="./src/gitpod/resources/runners/configurations/host_authentication_tokens.py">list</a>(\*\*<a href="src/gitpod/types/runners/configurations/host_authentication_token_list_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/host_authentication_token.py">SyncTokensPage[HostAuthenticationToken]</a></code> +- <code title="post /gitpod.v1.RunnerConfigurationService/DeleteHostAuthenticationToken">client.runners.configurations.host_authentication_tokens.<a href="./src/gitpod/resources/runners/configurations/host_authentication_tokens.py">delete</a>(\*\*<a href="src/gitpod/types/runners/configurations/host_authentication_token_delete_params.py">params</a>) -> object</code> + +### Schema + +Types: + +```python +from gitpod.types.runners.configurations import RunnerConfigurationSchema, SchemaRetrieveResponse +``` + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/GetRunnerConfigurationSchema">client.runners.configurations.schema.<a href="./src/gitpod/resources/runners/configurations/schema.py">retrieve</a>(\*\*<a href="src/gitpod/types/runners/configurations/schema_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/schema_retrieve_response.py">SchemaRetrieveResponse</a></code> + +### ScmIntegrations + +Types: + +```python +from gitpod.types.runners.configurations import ( + ScmIntegration, + ScmIntegrationOAuthConfig, + ScmIntegrationCreateResponse, + ScmIntegrationRetrieveResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/CreateSCMIntegration">client.runners.configurations.scm_integrations.<a href="./src/gitpod/resources/runners/configurations/scm_integrations.py">create</a>(\*\*<a href="src/gitpod/types/runners/configurations/scm_integration_create_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/scm_integration_create_response.py">ScmIntegrationCreateResponse</a></code> +- <code title="post /gitpod.v1.RunnerConfigurationService/GetSCMIntegration">client.runners.configurations.scm_integrations.<a href="./src/gitpod/resources/runners/configurations/scm_integrations.py">retrieve</a>(\*\*<a href="src/gitpod/types/runners/configurations/scm_integration_retrieve_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/scm_integration_retrieve_response.py">ScmIntegrationRetrieveResponse</a></code> +- <code title="post /gitpod.v1.RunnerConfigurationService/UpdateSCMIntegration">client.runners.configurations.scm_integrations.<a href="./src/gitpod/resources/runners/configurations/scm_integrations.py">update</a>(\*\*<a href="src/gitpod/types/runners/configurations/scm_integration_update_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/ListSCMIntegrations">client.runners.configurations.scm_integrations.<a href="./src/gitpod/resources/runners/configurations/scm_integrations.py">list</a>(\*\*<a href="src/gitpod/types/runners/configurations/scm_integration_list_params.py">params</a>) -> <a href="./src/gitpod/types/runners/configurations/scm_integration.py">SyncIntegrationsPage[ScmIntegration]</a></code> +- <code title="post /gitpod.v1.RunnerConfigurationService/DeleteSCMIntegration">client.runners.configurations.scm_integrations.<a href="./src/gitpod/resources/runners/configurations/scm_integrations.py">delete</a>(\*\*<a href="src/gitpod/types/runners/configurations/scm_integration_delete_params.py">params</a>) -> object</code> + +## Policies + +Types: + +```python +from gitpod.types.runners import ( + RunnerPolicy, + RunnerRole, + PolicyCreateResponse, + PolicyUpdateResponse, +) +``` + +Methods: + +- <code title="post /gitpod.v1.RunnerService/CreateRunnerPolicy">client.runners.policies.<a href="./src/gitpod/resources/runners/policies.py">create</a>(\*\*<a href="src/gitpod/types/runners/policy_create_params.py">params</a>) -> <a href="./src/gitpod/types/runners/policy_create_response.py">PolicyCreateResponse</a></code> +- <code title="post /gitpod.v1.RunnerService/UpdateRunnerPolicy">client.runners.policies.<a href="./src/gitpod/resources/runners/policies.py">update</a>(\*\*<a href="src/gitpod/types/runners/policy_update_params.py">params</a>) -> <a href="./src/gitpod/types/runners/policy_update_response.py">PolicyUpdateResponse</a></code> +- <code title="post /gitpod.v1.RunnerService/ListRunnerPolicies">client.runners.policies.<a href="./src/gitpod/resources/runners/policies.py">list</a>(\*\*<a href="src/gitpod/types/runners/policy_list_params.py">params</a>) -> <a href="./src/gitpod/types/runners/runner_policy.py">SyncPoliciesPage[RunnerPolicy]</a></code> +- <code title="post /gitpod.v1.RunnerService/DeleteRunnerPolicy">client.runners.policies.<a href="./src/gitpod/resources/runners/policies.py">delete</a>(\*\*<a href="src/gitpod/types/runners/policy_delete_params.py">params</a>) -> object</code> + +# Secrets + +Types: + +```python +from gitpod.types import Secret, SecretScope, SecretCreateResponse, SecretGetValueResponse +``` + +Methods: + +- <code title="post /gitpod.v1.SecretService/CreateSecret">client.secrets.<a href="./src/gitpod/resources/secrets.py">create</a>(\*\*<a href="src/gitpod/types/secret_create_params.py">params</a>) -> <a href="./src/gitpod/types/secret_create_response.py">SecretCreateResponse</a></code> +- <code title="post /gitpod.v1.SecretService/ListSecrets">client.secrets.<a href="./src/gitpod/resources/secrets.py">list</a>(\*\*<a href="src/gitpod/types/secret_list_params.py">params</a>) -> <a href="./src/gitpod/types/secret.py">SyncSecretsPage[Secret]</a></code> +- <code title="post /gitpod.v1.SecretService/DeleteSecret">client.secrets.<a href="./src/gitpod/resources/secrets.py">delete</a>(\*\*<a href="src/gitpod/types/secret_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.SecretService/GetSecretValue">client.secrets.<a href="./src/gitpod/resources/secrets.py">get_value</a>(\*\*<a href="src/gitpod/types/secret_get_value_params.py">params</a>) -> <a href="./src/gitpod/types/secret_get_value_response.py">SecretGetValueResponse</a></code> +- <code title="post /gitpod.v1.SecretService/UpdateSecretValue">client.secrets.<a href="./src/gitpod/resources/secrets.py">update_value</a>(\*\*<a href="src/gitpod/types/secret_update_value_params.py">params</a>) -> object</code> + +# Usage + +Types: + +```python +from gitpod.types import EnvironmentUsageRecord +``` + +Methods: + +- <code title="post /gitpod.v1.UsageService/ListEnvironmentUsageRecords">client.usage.<a href="./src/gitpod/resources/usage.py">list_environment_runtime_records</a>(\*\*<a href="src/gitpod/types/usage_list_environment_runtime_records_params.py">params</a>) -> <a href="./src/gitpod/types/environment_usage_record.py">SyncRecordsPage[EnvironmentUsageRecord]</a></code> + +# Users + +Types: + +```python +from gitpod.types import User, UserGetAuthenticatedUserResponse +``` + +Methods: + +- <code title="post /gitpod.v1.UserService/GetAuthenticatedUser">client.users.<a href="./src/gitpod/resources/users/users.py">get_authenticated_user</a>(\*\*<a href="src/gitpod/types/user_get_authenticated_user_params.py">params</a>) -> <a href="./src/gitpod/types/user_get_authenticated_user_response.py">UserGetAuthenticatedUserResponse</a></code> +- <code title="post /gitpod.v1.UserService/SetSuspended">client.users.<a href="./src/gitpod/resources/users/users.py">set_suspended</a>(\*\*<a href="src/gitpod/types/user_set_suspended_params.py">params</a>) -> object</code> + +## Dotfiles + +Types: + +```python +from gitpod.types.users import DotfilesConfiguration, DotfileGetResponse +``` + +Methods: + +- <code title="post /gitpod.v1.UserService/GetDotfilesConfiguration">client.users.dotfiles.<a href="./src/gitpod/resources/users/dotfiles.py">get</a>(\*\*<a href="src/gitpod/types/users/dotfile_get_params.py">params</a>) -> <a href="./src/gitpod/types/users/dotfile_get_response.py">DotfileGetResponse</a></code> +- <code title="post /gitpod.v1.UserService/SetDotfilesConfiguration">client.users.dotfiles.<a href="./src/gitpod/resources/users/dotfiles.py">set</a>(\*\*<a href="src/gitpod/types/users/dotfile_set_params.py">params</a>) -> object</code> + +## Pats + +Types: + +```python +from gitpod.types.users import PersonalAccessToken, PatGetResponse +``` + +Methods: + +- <code title="post /gitpod.v1.UserService/ListPersonalAccessTokens">client.users.pats.<a href="./src/gitpod/resources/users/pats.py">list</a>(\*\*<a href="src/gitpod/types/users/pat_list_params.py">params</a>) -> <a href="./src/gitpod/types/users/personal_access_token.py">SyncPersonalAccessTokensPage[PersonalAccessToken]</a></code> +- <code title="post /gitpod.v1.UserService/DeletePersonalAccessToken">client.users.pats.<a href="./src/gitpod/resources/users/pats.py">delete</a>(\*\*<a href="src/gitpod/types/users/pat_delete_params.py">params</a>) -> object</code> +- <code title="post /gitpod.v1.UserService/GetPersonalAccessToken">client.users.pats.<a href="./src/gitpod/resources/users/pats.py">get</a>(\*\*<a href="src/gitpod/types/users/pat_get_params.py">params</a>) -> <a href="./src/gitpod/types/users/pat_get_response.py">PatGetResponse</a></code> diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000..b845b0f --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${PYPI_TOKEN}" ]; then + errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") +fi + +lenErrors=${#errors[@]} + +if [[ lenErrors -gt 0 ]]; then + echo -e "Found the following errors in the release environment:\n" + + for error in "${errors[@]}"; do + echo -e "- $error\n" + done + + exit 1 +fi + +echo "The environment is ready to push releases!" diff --git a/bin/publish-pypi b/bin/publish-pypi new file mode 100644 index 0000000..826054e --- /dev/null +++ b/bin/publish-pypi @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -eux +mkdir -p dist +rye build --clean +rye publish --yes --token=$PYPI_TOKEN diff --git a/examples/.keep b/examples/.keep new file mode 100644 index 0000000..d8c73e9 --- /dev/null +++ b/examples/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store example files demonstrating usage of this SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..e2d1320 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,50 @@ +[mypy] +pretty = True +show_error_codes = True + +# Exclude _files.py because mypy isn't smart enough to apply +# the correct type narrowing and as this is an internal module +# it's fine to just use Pyright. +# +# We also exclude our `tests` as mypy doesn't always infer +# types correctly and Pyright will still catch any type errors. +exclude = ^(src/gitpod/_files\.py|_dev/.*\.py|tests/.*)$ + +strict_equality = True +implicit_reexport = True +check_untyped_defs = True +no_implicit_optional = True + +warn_return_any = True +warn_unreachable = True +warn_unused_configs = True + +# Turn these options off as it could cause conflicts +# with the Pyright options. +warn_unused_ignores = False +warn_redundant_casts = False + +disallow_any_generics = True +disallow_untyped_defs = True +disallow_untyped_calls = True +disallow_subclassing_any = True +disallow_incomplete_defs = True +disallow_untyped_decorators = True +cache_fine_grained = True + +# By default, mypy reports an error if you assign a value to the result +# of a function call that doesn't return anything. We do this in our test +# cases: +# ``` +# result = ... +# assert result is None +# ``` +# Changing this codegen to make mypy happy would increase complexity +# and would not be worth it. +disable_error_code = func-returns-value,overload-cannot-match + +# https://github.com/python/mypy/issues/12162 +[mypy.overrides] +module = "black.files.*" +ignore_errors = true +ignore_missing_imports = true diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..53bca7f --- /dev/null +++ b/noxfile.py @@ -0,0 +1,9 @@ +import nox + + +@nox.session(reuse_venv=True, name="test-pydantic-v1") +def test_pydantic_v1(session: nox.Session) -> None: + session.install("-r", "requirements-dev.lock") + session.install("pydantic<2") + + session.run("pytest", "--showlocals", "--ignore=tests/functional", *session.posargs) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5f4250e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,211 @@ +[project] +name = "gitpod-sdk" +version = "0.3.0" +description = "The official Python library for the gitpod API" +dynamic = ["readme"] +license = "Apache-2.0" +authors = [ +{ name = "Gitpod", email = "dev-feedback@gitpod.com" }, +] +dependencies = [ + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.10, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", +] +requires-python = ">= 3.8" +classifiers = [ + "Typing :: Typed", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Operating System :: OS Independent", + "Operating System :: POSIX", + "Operating System :: MacOS", + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows", + "Topic :: Software Development :: Libraries :: Python Modules", + "License :: OSI Approved :: Apache Software License" +] + +[project.urls] +Homepage = "https://github.com/gitpod-io/gitpod-sdk-python" +Repository = "https://github.com/gitpod-io/gitpod-sdk-python" + +[project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] + +[tool.rye] +managed = true +# version pins are in requirements-dev.lock +dev-dependencies = [ + "pyright==1.1.399", + "mypy", + "respx", + "pytest", + "pytest-asyncio", + "ruff", + "time-machine", + "nox", + "dirty-equals>=0.6.0", + "importlib-metadata>=6.7.0", + "rich>=13.7.1", + "nest_asyncio==1.6.0", + "pytest-xdist>=3.6.1", +] + +[tool.rye.scripts] +format = { chain = [ + "format:ruff", + "format:docs", + "fix:ruff", + # run formatting again to fix any inconsistencies when imports are stripped + "format:ruff", +]} +"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" +"format:ruff" = "ruff format" + +"lint" = { chain = [ + "check:ruff", + "typecheck", + "check:importable", +]} +"check:ruff" = "ruff check ." +"fix:ruff" = "ruff check --fix ." + +"check:importable" = "python -c 'import gitpod'" + +typecheck = { chain = [ + "typecheck:pyright", + "typecheck:mypy" +]} +"typecheck:pyright" = "pyright" +"typecheck:verify-types" = "pyright --verifytypes gitpod --ignoreexternal" +"typecheck:mypy" = "mypy ." + +[build-system] +requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"] +build-backend = "hatchling.build" + +[tool.hatch.build] +include = [ + "src/*" +] + +[tool.hatch.build.targets.wheel] +packages = ["src/gitpod"] + +[tool.hatch.build.targets.sdist] +# Basically everything except hidden files/directories (such as .github, .devcontainers, .python-version, etc) +include = [ + "/*.toml", + "/*.json", + "/*.lock", + "/*.md", + "/mypy.ini", + "/noxfile.py", + "bin/*", + "examples/*", + "src/*", + "tests/*", +] + +[tool.hatch.metadata.hooks.fancy-pypi-readme] +content-type = "text/markdown" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "README.md" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] +# replace relative links with absolute links +pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)' +replacement = '[\1](https://github.com/gitpod-io/gitpod-sdk-python/tree/main/\g<2>)' + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "--tb=short -n auto" +xfail_strict = true +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "session" +filterwarnings = [ + "error" +] + +[tool.pyright] +# this enables practically every flag given by pyright. +# there are a couple of flags that are still disabled by +# default in strict mode as they are experimental and niche. +typeCheckingMode = "strict" +pythonVersion = "3.8" + +exclude = [ + "_dev", + ".venv", + ".nox", +] + +reportImplicitOverride = true +reportOverlappingOverload = false + +reportImportCycles = false +reportPrivateUsage = false + +[tool.ruff] +line-length = 120 +output-format = "grouped" +target-version = "py37" + +[tool.ruff.format] +docstring-code-format = true + +[tool.ruff.lint] +select = [ + # isort + "I", + # bugbear rules + "B", + # remove unused imports + "F401", + # bare except statements + "E722", + # unused arguments + "ARG", + # print statements + "T201", + "T203", + # misuse of typing.TYPE_CHECKING + "TC004", + # import rules + "TID251", +] +ignore = [ + # mutable defaults + "B006", +] +unfixable = [ + # disable auto fix for print statements + "T201", + "T203", +] + +[tool.ruff.lint.flake8-tidy-imports.banned-api] +"functools.lru_cache".msg = "This function does not retain type information for the wrapped function's arguments; The `lru_cache` function from `_utils` should be used instead" + +[tool.ruff.lint.isort] +length-sort = true +length-sort-straight = true +combine-as-imports = true +extra-standard-library = ["typing_extensions"] +known-first-party = ["gitpod", "tests"] + +[tool.ruff.lint.per-file-ignores] +"bin/**.py" = ["T201", "T203"] +"scripts/**.py" = ["T201", "T203"] +"tests/**.py" = ["T201", "T203"] +"examples/**.py" = ["T201", "T203"] diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..024bdf6 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,66 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "python", + "extra-files": [ + "src/gitpod/_version.py" + ] +} \ No newline at end of file diff --git a/requirements-dev.lock b/requirements-dev.lock new file mode 100644 index 0000000..d496425 --- /dev/null +++ b/requirements-dev.lock @@ -0,0 +1,135 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: true +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via gitpod-sdk + # via httpx-aiohttp +aiosignal==1.3.2 + # via aiohttp +annotated-types==0.6.0 + # via pydantic +anyio==4.4.0 + # via gitpod-sdk + # via httpx +argcomplete==3.1.2 + # via nox +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp +certifi==2023.7.22 + # via httpcore + # via httpx +colorlog==6.7.0 + # via nox +dirty-equals==0.6.0 +distlib==0.3.7 + # via virtualenv +distro==1.8.0 + # via gitpod-sdk +exceptiongroup==1.2.2 + # via anyio + # via pytest +execnet==2.1.1 + # via pytest-xdist +filelock==3.12.4 + # via virtualenv +frozenlist==1.6.2 + # via aiohttp + # via aiosignal +h11==0.16.0 + # via httpcore +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via gitpod-sdk + # via httpx-aiohttp + # via respx +httpx-aiohttp==0.1.8 + # via gitpod-sdk +idna==3.4 + # via anyio + # via httpx + # via yarl +importlib-metadata==7.0.0 +iniconfig==2.0.0 + # via pytest +markdown-it-py==3.0.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +multidict==6.4.4 + # via aiohttp + # via yarl +mypy==1.14.1 +mypy-extensions==1.0.0 + # via mypy +nest-asyncio==1.6.0 +nodeenv==1.8.0 + # via pyright +nox==2023.4.22 +packaging==23.2 + # via nox + # via pytest +platformdirs==3.11.0 + # via virtualenv +pluggy==1.5.0 + # via pytest +propcache==0.3.1 + # via aiohttp + # via yarl +pydantic==2.10.3 + # via gitpod-sdk +pydantic-core==2.27.1 + # via pydantic +pygments==2.18.0 + # via rich +pyright==1.1.399 +pytest==8.3.3 + # via pytest-asyncio + # via pytest-xdist +pytest-asyncio==0.24.0 +pytest-xdist==3.7.0 +python-dateutil==2.8.2 + # via time-machine +pytz==2023.3.post1 + # via dirty-equals +respx==0.22.0 +rich==13.7.1 +ruff==0.9.4 +setuptools==68.2.2 + # via nodeenv +six==1.16.0 + # via python-dateutil +sniffio==1.3.0 + # via anyio + # via gitpod-sdk +time-machine==2.9.0 +tomli==2.0.2 + # via mypy + # via pytest +typing-extensions==4.12.2 + # via anyio + # via gitpod-sdk + # via multidict + # via mypy + # via pydantic + # via pydantic-core + # via pyright +virtualenv==20.24.5 + # via nox +yarl==1.20.0 + # via aiohttp +zipp==3.17.0 + # via importlib-metadata diff --git a/requirements.lock b/requirements.lock new file mode 100644 index 0000000..c0455c9 --- /dev/null +++ b/requirements.lock @@ -0,0 +1,72 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: true +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via gitpod-sdk + # via httpx-aiohttp +aiosignal==1.3.2 + # via aiohttp +annotated-types==0.6.0 + # via pydantic +anyio==4.4.0 + # via gitpod-sdk + # via httpx +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp +certifi==2023.7.22 + # via httpcore + # via httpx +distro==1.8.0 + # via gitpod-sdk +exceptiongroup==1.2.2 + # via anyio +frozenlist==1.6.2 + # via aiohttp + # via aiosignal +h11==0.16.0 + # via httpcore +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via gitpod-sdk + # via httpx-aiohttp +httpx-aiohttp==0.1.8 + # via gitpod-sdk +idna==3.4 + # via anyio + # via httpx + # via yarl +multidict==6.4.4 + # via aiohttp + # via yarl +propcache==0.3.1 + # via aiohttp + # via yarl +pydantic==2.10.3 + # via gitpod-sdk +pydantic-core==2.27.1 + # via pydantic +sniffio==1.3.0 + # via anyio + # via gitpod-sdk +typing-extensions==4.12.2 + # via anyio + # via gitpod-sdk + # via multidict + # via pydantic + # via pydantic-core +yarl==1.20.0 + # via aiohttp diff --git a/scripts/bootstrap b/scripts/bootstrap new file mode 100755 index 0000000..e84fe62 --- /dev/null +++ b/scripts/bootstrap @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if ! command -v rye >/dev/null 2>&1 && [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then + brew bundle check >/dev/null 2>&1 || { + echo "==> Installing Homebrew dependencies…" + brew bundle + } +fi + +echo "==> Installing Python dependencies…" + +# experimental uv support makes installations significantly faster +rye config --set-bool behavior.use-uv=true + +rye sync --all-features diff --git a/scripts/format b/scripts/format new file mode 100755 index 0000000..667ec2d --- /dev/null +++ b/scripts/format @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running formatters" +rye run format diff --git a/scripts/lint b/scripts/lint new file mode 100755 index 0000000..6a98ee4 --- /dev/null +++ b/scripts/lint @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running lints" +rye run lint + +echo "==> Making sure it imports" +rye run python -c 'import gitpod' diff --git a/scripts/mock b/scripts/mock new file mode 100755 index 0000000..d2814ae --- /dev/null +++ b/scripts/mock @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [[ -n "$1" && "$1" != '--'* ]]; then + URL="$1" + shift +else + URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" +fi + +# Check if the URL is empty +if [ -z "$URL" ]; then + echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" + exit 1 +fi + +echo "==> Starting mock server with URL ${URL}" + +# Run prism mock on the given spec +if [ "$1" == "--daemon" ]; then + npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & + + # Wait for server to come online + echo -n "Waiting for server" + while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + echo -n "." + sleep 0.1 + done + + if grep -q "✖ fatal" ".prism.log"; then + cat .prism.log + exit 1 + fi + + echo +else + npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" +fi diff --git a/scripts/test b/scripts/test new file mode 100755 index 0000000..2b87845 --- /dev/null +++ b/scripts/test @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +function prism_is_running() { + curl --silent "http://localhost:4010" >/dev/null 2>&1 +} + +kill_server_on_port() { + pids=$(lsof -t -i tcp:"$1" || echo "") + if [ "$pids" != "" ]; then + kill "$pids" + echo "Stopped $pids." + fi +} + +function is_overriding_api_base_url() { + [ -n "$TEST_API_BASE_URL" ] +} + +if ! is_overriding_api_base_url && ! prism_is_running ; then + # When we exit this script, make sure to kill the background mock server process + trap 'kill_server_on_port 4010' EXIT + + # Start the dev server + ./scripts/mock --daemon +fi + +if is_overriding_api_base_url ; then + echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" + echo +elif ! prism_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" + echo -e "running against your OpenAPI spec." + echo + echo -e "To run the server, pass in the path or url of your OpenAPI" + echo -e "spec to the prism command:" + echo + echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo + + exit 1 +else + echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo +fi + +export DEFER_PYDANTIC_BUILD=false + +echo "==> Running tests" +rye run pytest "$@" + +echo "==> Running Pydantic v1 tests" +rye run nox -s test-pydantic-v1 -- "$@" diff --git a/scripts/utils/ruffen-docs.py b/scripts/utils/ruffen-docs.py new file mode 100644 index 0000000..0cf2bd2 --- /dev/null +++ b/scripts/utils/ruffen-docs.py @@ -0,0 +1,167 @@ +# fork of https://github.com/asottile/blacken-docs adapted for ruff +from __future__ import annotations + +import re +import sys +import argparse +import textwrap +import contextlib +import subprocess +from typing import Match, Optional, Sequence, Generator, NamedTuple, cast + +MD_RE = re.compile( + r"(?P<before>^(?P<indent> *)```\s*python\n)" r"(?P<code>.*?)" r"(?P<after>^(?P=indent)```\s*$)", + re.DOTALL | re.MULTILINE, +) +MD_PYCON_RE = re.compile( + r"(?P<before>^(?P<indent> *)```\s*pycon\n)" r"(?P<code>.*?)" r"(?P<after>^(?P=indent)```.*$)", + re.DOTALL | re.MULTILINE, +) +PYCON_PREFIX = ">>> " +PYCON_CONTINUATION_PREFIX = "..." +PYCON_CONTINUATION_RE = re.compile( + rf"^{re.escape(PYCON_CONTINUATION_PREFIX)}( |$)", +) +DEFAULT_LINE_LENGTH = 100 + + +class CodeBlockError(NamedTuple): + offset: int + exc: Exception + + +def format_str( + src: str, +) -> tuple[str, Sequence[CodeBlockError]]: + errors: list[CodeBlockError] = [] + + @contextlib.contextmanager + def _collect_error(match: Match[str]) -> Generator[None, None, None]: + try: + yield + except Exception as e: + errors.append(CodeBlockError(match.start(), e)) + + def _md_match(match: Match[str]) -> str: + code = textwrap.dedent(match["code"]) + with _collect_error(match): + code = format_code_block(code) + code = textwrap.indent(code, match["indent"]) + return f"{match['before']}{code}{match['after']}" + + def _pycon_match(match: Match[str]) -> str: + code = "" + fragment = cast(Optional[str], None) + + def finish_fragment() -> None: + nonlocal code + nonlocal fragment + + if fragment is not None: + with _collect_error(match): + fragment = format_code_block(fragment) + fragment_lines = fragment.splitlines() + code += f"{PYCON_PREFIX}{fragment_lines[0]}\n" + for line in fragment_lines[1:]: + # Skip blank lines to handle Black adding a blank above + # functions within blocks. A blank line would end the REPL + # continuation prompt. + # + # >>> if True: + # ... def f(): + # ... pass + # ... + if line: + code += f"{PYCON_CONTINUATION_PREFIX} {line}\n" + if fragment_lines[-1].startswith(" "): + code += f"{PYCON_CONTINUATION_PREFIX}\n" + fragment = None + + indentation = None + for line in match["code"].splitlines(): + orig_line, line = line, line.lstrip() + if indentation is None and line: + indentation = len(orig_line) - len(line) + continuation_match = PYCON_CONTINUATION_RE.match(line) + if continuation_match and fragment is not None: + fragment += line[continuation_match.end() :] + "\n" + else: + finish_fragment() + if line.startswith(PYCON_PREFIX): + fragment = line[len(PYCON_PREFIX) :] + "\n" + else: + code += orig_line[indentation:] + "\n" + finish_fragment() + return code + + def _md_pycon_match(match: Match[str]) -> str: + code = _pycon_match(match) + code = textwrap.indent(code, match["indent"]) + return f"{match['before']}{code}{match['after']}" + + src = MD_RE.sub(_md_match, src) + src = MD_PYCON_RE.sub(_md_pycon_match, src) + return src, errors + + +def format_code_block(code: str) -> str: + return subprocess.check_output( + [ + sys.executable, + "-m", + "ruff", + "format", + "--stdin-filename=script.py", + f"--line-length={DEFAULT_LINE_LENGTH}", + ], + encoding="utf-8", + input=code, + ) + + +def format_file( + filename: str, + skip_errors: bool, +) -> int: + with open(filename, encoding="UTF-8") as f: + contents = f.read() + new_contents, errors = format_str(contents) + for error in errors: + lineno = contents[: error.offset].count("\n") + 1 + print(f"{filename}:{lineno}: code block parse error {error.exc}") + if errors and not skip_errors: + return 1 + if contents != new_contents: + print(f"{filename}: Rewriting...") + with open(filename, "w", encoding="UTF-8") as f: + f.write(new_contents) + return 0 + else: + return 0 + + +def main(argv: Sequence[str] | None = None) -> int: + parser = argparse.ArgumentParser() + parser.add_argument( + "-l", + "--line-length", + type=int, + default=DEFAULT_LINE_LENGTH, + ) + parser.add_argument( + "-S", + "--skip-string-normalization", + action="store_true", + ) + parser.add_argument("-E", "--skip-errors", action="store_true") + parser.add_argument("filenames", nargs="*") + args = parser.parse_args(argv) + + retv = 0 + for filename in args.filenames: + retv |= format_file(filename, skip_errors=args.skip_errors) + return retv + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh new file mode 100755 index 0000000..ea68293 --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -exuo pipefail + +FILENAME=$(basename dist/*.whl) + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: binary/octet-stream" \ + --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) + +if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then + echo -e "\033[32mUploaded build to Stainless storage.\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/gitpod-python/$SHA/$FILENAME'\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi diff --git a/src/gitpod/__init__.py b/src/gitpod/__init__.py new file mode 100644 index 0000000..f2a5eb2 --- /dev/null +++ b/src/gitpod/__init__.py @@ -0,0 +1,90 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import typing as _t + +from . import types +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes +from ._utils import file_from_path +from ._client import Client, Gitpod, Stream, Timeout, Transport, AsyncClient, AsyncGitpod, AsyncStream, RequestOptions +from ._models import BaseModel +from ._version import __title__, __version__ +from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse +from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS +from ._exceptions import ( + APIError, + GitpodError, + ConflictError, + NotFoundError, + APIStatusError, + RateLimitError, + APITimeoutError, + BadRequestError, + APIConnectionError, + AuthenticationError, + InternalServerError, + PermissionDeniedError, + UnprocessableEntityError, + APIResponseValidationError, +) +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient +from ._utils._logs import setup_logging as _setup_logging + +__all__ = [ + "types", + "__version__", + "__title__", + "NoneType", + "Transport", + "ProxiesTypes", + "NotGiven", + "NOT_GIVEN", + "Omit", + "GitpodError", + "APIError", + "APIStatusError", + "APITimeoutError", + "APIConnectionError", + "APIResponseValidationError", + "BadRequestError", + "AuthenticationError", + "PermissionDeniedError", + "NotFoundError", + "ConflictError", + "UnprocessableEntityError", + "RateLimitError", + "InternalServerError", + "Timeout", + "RequestOptions", + "Client", + "AsyncClient", + "Stream", + "AsyncStream", + "Gitpod", + "AsyncGitpod", + "file_from_path", + "BaseModel", + "DEFAULT_TIMEOUT", + "DEFAULT_MAX_RETRIES", + "DEFAULT_CONNECTION_LIMITS", + "DefaultHttpxClient", + "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", +] + +if not _t.TYPE_CHECKING: + from ._utils._resources_proxy import resources as resources + +_setup_logging() + +# Update the __module__ attribute for exported symbols so that +# error messages point to this module instead of the module +# it was originally defined in, e.g. +# gitpod._exceptions.NotFoundError -> gitpod.NotFoundError +__locals = locals() +for __name in __all__: + if not __name.startswith("__"): + try: + __locals[__name].__module__ = "gitpod" + except (TypeError, AttributeError): + # Some of our exported symbols are builtins which we can't set attributes for. + pass diff --git a/src/gitpod/_base_client.py b/src/gitpod/_base_client.py new file mode 100644 index 0000000..550b73f --- /dev/null +++ b/src/gitpod/_base_client.py @@ -0,0 +1,1992 @@ +from __future__ import annotations + +import sys +import json +import time +import uuid +import email +import asyncio +import inspect +import logging +import platform +import email.utils +from types import TracebackType +from random import random +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Type, + Union, + Generic, + Mapping, + TypeVar, + Iterable, + Iterator, + Optional, + Generator, + AsyncIterator, + cast, + overload, +) +from typing_extensions import Literal, override, get_origin + +import anyio +import httpx +import distro +import pydantic +from httpx import URL +from pydantic import PrivateAttr + +from . import _exceptions +from ._qs import Querystring +from ._files import to_httpx_files, async_to_httpx_files +from ._types import ( + NOT_GIVEN, + Body, + Omit, + Query, + Headers, + Timeout, + NotGiven, + ResponseT, + AnyMapping, + PostParser, + RequestFiles, + HttpxSendArgs, + RequestOptions, + HttpxRequestFiles, + ModelBuilderProtocol, +) +from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping +from ._compat import PYDANTIC_V2, model_copy, model_dump +from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type +from ._response import ( + APIResponse, + BaseAPIResponse, + AsyncAPIResponse, + extract_response_type, +) +from ._constants import ( + DEFAULT_TIMEOUT, + MAX_RETRY_DELAY, + DEFAULT_MAX_RETRIES, + INITIAL_RETRY_DELAY, + RAW_RESPONSE_HEADER, + OVERRIDE_CAST_TO_HEADER, + DEFAULT_CONNECTION_LIMITS, +) +from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder +from ._exceptions import ( + APIStatusError, + APITimeoutError, + APIConnectionError, + APIResponseValidationError, +) + +log: logging.Logger = logging.getLogger(__name__) + +# TODO: make base page type vars covariant +SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]") +AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]") + + +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) + +_StreamT = TypeVar("_StreamT", bound=Stream[Any]) +_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) + +if TYPE_CHECKING: + from httpx._config import ( + DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] + ) + + HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG +else: + try: + from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT + except ImportError: + # taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366 + HTTPX_DEFAULT_TIMEOUT = Timeout(5.0) + + +class PageInfo: + """Stores the necessary information to build the request to retrieve the next page. + + Either `url` or `params` must be set. + """ + + url: URL | NotGiven + params: Query | NotGiven + json: Body | NotGiven + + @overload + def __init__( + self, + *, + url: URL, + ) -> None: ... + + @overload + def __init__( + self, + *, + params: Query, + ) -> None: ... + + @overload + def __init__( + self, + *, + json: Body, + ) -> None: ... + + def __init__( + self, + *, + url: URL | NotGiven = NOT_GIVEN, + json: Body | NotGiven = NOT_GIVEN, + params: Query | NotGiven = NOT_GIVEN, + ) -> None: + self.url = url + self.json = json + self.params = params + + @override + def __repr__(self) -> str: + if self.url: + return f"{self.__class__.__name__}(url={self.url})" + if self.json: + return f"{self.__class__.__name__}(json={self.json})" + return f"{self.__class__.__name__}(params={self.params})" + + +class BasePage(GenericModel, Generic[_T]): + """ + Defines the core interface for pagination. + + Type Args: + ModelT: The pydantic model that represents an item in the response. + + Methods: + has_next_page(): Check if there is another page available + next_page_info(): Get the necessary information to make a request for the next page + """ + + _options: FinalRequestOptions = PrivateAttr() + _model: Type[_T] = PrivateAttr() + + def has_next_page(self) -> bool: + items = self._get_page_items() + if not items: + return False + return self.next_page_info() is not None + + def next_page_info(self) -> Optional[PageInfo]: ... + + def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body] + ... + + def _params_from_url(self, url: URL) -> httpx.QueryParams: + # TODO: do we have to preprocess params here? + return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params) + + def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: + options = model_copy(self._options) + options._strip_raw_response_header() + + if not isinstance(info.params, NotGiven): + options.params = {**options.params, **info.params} + return options + + if not isinstance(info.url, NotGiven): + params = self._params_from_url(info.url) + url = info.url.copy_with(params=params) + options.params = dict(url.params) + options.url = str(url) + return options + + if not isinstance(info.json, NotGiven): + if not is_mapping(info.json): + raise TypeError("Pagination is only supported with mappings") + + if not options.json_data: + options.json_data = {**info.json} + else: + if not is_mapping(options.json_data): + raise TypeError("Pagination is only supported with mappings") + + options.json_data = {**options.json_data, **info.json} + return options + + raise ValueError("Unexpected PageInfo state") + + +class BaseSyncPage(BasePage[_T], Generic[_T]): + _client: SyncAPIClient = pydantic.PrivateAttr() + + def _set_private_attributes( + self, + client: SyncAPIClient, + model: Type[_T], + options: FinalRequestOptions, + ) -> None: + if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + + self._model = model + self._client = client + self._options = options + + # Pydantic uses a custom `__iter__` method to support casting BaseModels + # to dictionaries. e.g. dict(model). + # As we want to support `for item in page`, this is inherently incompatible + # with the default pydantic behaviour. It is not possible to support both + # use cases at once. Fortunately, this is not a big deal as all other pydantic + # methods should continue to work as expected as there is an alternative method + # to cast a model to a dictionary, model.dict(), which is used internally + # by pydantic. + def __iter__(self) -> Iterator[_T]: # type: ignore + for page in self.iter_pages(): + for item in page._get_page_items(): + yield item + + def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]: + page = self + while True: + yield page + if page.has_next_page(): + page = page.get_next_page() + else: + return + + def get_next_page(self: SyncPageT) -> SyncPageT: + info = self.next_page_info() + if not info: + raise RuntimeError( + "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." + ) + + options = self._info_to_options(info) + return self._client._request_api_list(self._model, page=self.__class__, options=options) + + +class AsyncPaginator(Generic[_T, AsyncPageT]): + def __init__( + self, + client: AsyncAPIClient, + options: FinalRequestOptions, + page_cls: Type[AsyncPageT], + model: Type[_T], + ) -> None: + self._model = model + self._client = client + self._options = options + self._page_cls = page_cls + + def __await__(self) -> Generator[Any, None, AsyncPageT]: + return self._get_page().__await__() + + async def _get_page(self) -> AsyncPageT: + def _parser(resp: AsyncPageT) -> AsyncPageT: + resp._set_private_attributes( + model=self._model, + options=self._options, + client=self._client, + ) + return resp + + self._options.post_parser = _parser + + return await self._client.request(self._page_cls, self._options) + + async def __aiter__(self) -> AsyncIterator[_T]: + # https://github.com/microsoft/pyright/issues/3464 + page = cast( + AsyncPageT, + await self, # type: ignore + ) + async for item in page: + yield item + + +class BaseAsyncPage(BasePage[_T], Generic[_T]): + _client: AsyncAPIClient = pydantic.PrivateAttr() + + def _set_private_attributes( + self, + model: Type[_T], + client: AsyncAPIClient, + options: FinalRequestOptions, + ) -> None: + if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + + self._model = model + self._client = client + self._options = options + + async def __aiter__(self) -> AsyncIterator[_T]: + async for page in self.iter_pages(): + for item in page._get_page_items(): + yield item + + async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]: + page = self + while True: + yield page + if page.has_next_page(): + page = await page.get_next_page() + else: + return + + async def get_next_page(self: AsyncPageT) -> AsyncPageT: + info = self.next_page_info() + if not info: + raise RuntimeError( + "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." + ) + + options = self._info_to_options(info) + return await self._client._request_api_list(self._model, page=self.__class__, options=options) + + +_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient]) +_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]]) + + +class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]): + _client: _HttpxClientT + _version: str + _base_url: URL + max_retries: int + timeout: Union[float, Timeout, None] + _strict_response_validation: bool + _idempotency_header: str | None + _default_stream_cls: type[_DefaultStreamT] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + _strict_response_validation: bool, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None = DEFAULT_TIMEOUT, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + ) -> None: + self._version = version + self._base_url = self._enforce_trailing_slash(URL(base_url)) + self.max_retries = max_retries + self.timeout = timeout + self._custom_headers = custom_headers or {} + self._custom_query = custom_query or {} + self._strict_response_validation = _strict_response_validation + self._idempotency_header = None + self._platform: Platform | None = None + + if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] + raise TypeError( + "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `gitpod.DEFAULT_MAX_RETRIES`" + ) + + def _enforce_trailing_slash(self, url: URL) -> URL: + if url.raw_path.endswith(b"/"): + return url + return url.copy_with(raw_path=url.raw_path + b"/") + + def _make_status_error_from_response( + self, + response: httpx.Response, + ) -> APIStatusError: + if response.is_closed and not response.is_stream_consumed: + # We can't read the response body as it has been closed + # before it was read. This can happen if an event hook + # raises a status error. + body = None + err_msg = f"Error code: {response.status_code}" + else: + err_text = response.text.strip() + body = err_text + + try: + body = json.loads(err_text) + err_msg = f"Error code: {response.status_code} - {body}" + except Exception: + err_msg = err_text or f"Error code: {response.status_code}" + + return self._make_status_error(err_msg, body=body, response=response) + + def _make_status_error( + self, + err_msg: str, + *, + body: object, + response: httpx.Response, + ) -> _exceptions.APIStatusError: + raise NotImplementedError() + + def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers: + custom_headers = options.headers or {} + headers_dict = _merge_mappings(self.default_headers, custom_headers) + self._validate_headers(headers_dict, custom_headers) + + # headers are case-insensitive while dictionaries are not. + headers = httpx.Headers(headers_dict) + + idempotency_header = self._idempotency_header + if idempotency_header and options.idempotency_key and idempotency_header not in headers: + headers[idempotency_header] = options.idempotency_key + + # Don't set these headers if they were already set or removed by the caller. We check + # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. + lower_custom_headers = [header.lower() for header in custom_headers] + if "x-stainless-retry-count" not in lower_custom_headers: + headers["x-stainless-retry-count"] = str(retries_taken) + if "x-stainless-read-timeout" not in lower_custom_headers: + timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout + if isinstance(timeout, Timeout): + timeout = timeout.read + if timeout is not None: + headers["x-stainless-read-timeout"] = str(timeout) + + return headers + + def _prepare_url(self, url: str) -> URL: + """ + Merge a URL argument together with any 'base_url' on the client, + to create the URL used for the outgoing request. + """ + # Copied from httpx's `_merge_url` method. + merge_url = URL(url) + if merge_url.is_relative_url: + merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") + return self.base_url.copy_with(raw_path=merge_raw_path) + + return merge_url + + def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder: + return SSEDecoder() + + def _build_request( + self, + options: FinalRequestOptions, + *, + retries_taken: int = 0, + ) -> httpx.Request: + if log.isEnabledFor(logging.DEBUG): + log.debug("Request options: %s", model_dump(options, exclude_unset=True)) + + kwargs: dict[str, Any] = {} + + json_data = options.json_data + if options.extra_json is not None: + if json_data is None: + json_data = cast(Body, options.extra_json) + elif is_mapping(json_data): + json_data = _merge_mappings(json_data, options.extra_json) + else: + raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") + + headers = self._build_headers(options, retries_taken=retries_taken) + params = _merge_mappings(self.default_query, options.params) + content_type = headers.get("Content-Type") + files = options.files + + # If the given Content-Type header is multipart/form-data then it + # has to be removed so that httpx can generate the header with + # additional information for us as it has to be in this form + # for the server to be able to correctly parse the request: + # multipart/form-data; boundary=---abc-- + if content_type is not None and content_type.startswith("multipart/form-data"): + if "boundary" not in content_type: + # only remove the header if the boundary hasn't been explicitly set + # as the caller doesn't want httpx to come up with their own boundary + headers.pop("Content-Type") + + # As we are now sending multipart/form-data instead of application/json + # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding + if json_data: + if not is_dict(json_data): + raise TypeError( + f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead." + ) + kwargs["data"] = self._serialize_multipartform(json_data) + + # httpx determines whether or not to send a "multipart/form-data" + # request based on the truthiness of the "files" argument. + # This gets around that issue by generating a dict value that + # evaluates to true. + # + # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 + if not files: + files = cast(HttpxRequestFiles, ForceMultipartDict()) + + prepared_url = self._prepare_url(options.url) + if "_" in prepared_url.host: + # work around https://github.com/encode/httpx/discussions/2880 + kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + + is_body_allowed = options.method.lower() != "get" + + if is_body_allowed: + kwargs["json"] = json_data if is_given(json_data) else None + kwargs["files"] = files + else: + headers.pop("Content-Type", None) + kwargs.pop("data", None) + + # TODO: report this error to httpx + return self._client.build_request( # pyright: ignore[reportUnknownMemberType] + headers=headers, + timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout, + method=options.method, + url=prepared_url, + # the `Query` type that we use is incompatible with qs' + # `Params` type as it needs to be typed as `Mapping[str, object]` + # so that passing a `TypedDict` doesn't cause an error. + # https://github.com/microsoft/pyright/issues/3526#event-6715453066 + params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, + **kwargs, + ) + + def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]: + items = self.qs.stringify_items( + # TODO: type ignore is required as stringify_items is well typed but we can't be + # well typed without heavy validation. + data, # type: ignore + array_format="brackets", + ) + serialized: dict[str, object] = {} + for key, value in items: + existing = serialized.get(key) + + if not existing: + serialized[key] = value + continue + + # If a value has already been set for this key then that + # means we're sending data like `array[]=[1, 2, 3]` and we + # need to tell httpx that we want to send multiple values with + # the same key which is done by using a list or a tuple. + # + # Note: 2d arrays should never result in the same key at both + # levels so it's safe to assume that if the value is a list, + # it was because we changed it to be a list. + if is_list(existing): + existing.append(value) + else: + serialized[key] = [existing, value] + + return serialized + + def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]: + if not is_given(options.headers): + return cast_to + + # make a copy of the headers so we don't mutate user-input + headers = dict(options.headers) + + # we internally support defining a temporary header to override the + # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` + # see _response.py for implementation details + override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, NOT_GIVEN) + if is_given(override_cast_to): + options.headers = headers + return cast(Type[ResponseT], override_cast_to) + + return cast_to + + def _should_stream_response_body(self, request: httpx.Request) -> bool: + return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return] + + def _process_response_data( + self, + *, + data: object, + cast_to: type[ResponseT], + response: httpx.Response, + ) -> ResponseT: + if data is None: + return cast(ResponseT, None) + + if cast_to is object: + return cast(ResponseT, data) + + try: + if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol): + return cast(ResponseT, cast_to.build(response=response, data=data)) + + if self._strict_response_validation: + return cast(ResponseT, validate_type(type_=cast_to, value=data)) + + return cast(ResponseT, construct_type(type_=cast_to, value=data)) + except pydantic.ValidationError as err: + raise APIResponseValidationError(response=response, body=data) from err + + @property + def qs(self) -> Querystring: + return Querystring() + + @property + def custom_auth(self) -> httpx.Auth | None: + return None + + @property + def auth_headers(self) -> dict[str, str]: + return {} + + @property + def default_headers(self) -> dict[str, str | Omit]: + return { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": self.user_agent, + **self.platform_headers(), + **self.auth_headers, + **self._custom_headers, + } + + @property + def default_query(self) -> dict[str, object]: + return { + **self._custom_query, + } + + def _validate_headers( + self, + headers: Headers, # noqa: ARG002 + custom_headers: Headers, # noqa: ARG002 + ) -> None: + """Validate the given default headers and custom headers. + + Does nothing by default. + """ + return + + @property + def user_agent(self) -> str: + return f"{self.__class__.__name__}/Python {self._version}" + + @property + def base_url(self) -> URL: + return self._base_url + + @base_url.setter + def base_url(self, url: URL | str) -> None: + self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url)) + + def platform_headers(self) -> Dict[str, str]: + # the actual implementation is in a separate `lru_cache` decorated + # function because adding `lru_cache` to methods will leak memory + # https://github.com/python/cpython/issues/88476 + return platform_headers(self._version, platform=self._platform) + + def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None: + """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified. + + About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After + See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax + """ + if response_headers is None: + return None + + # First, try the non-standard `retry-after-ms` header for milliseconds, + # which is more precise than integer-seconds `retry-after` + try: + retry_ms_header = response_headers.get("retry-after-ms", None) + return float(retry_ms_header) / 1000 + except (TypeError, ValueError): + pass + + # Next, try parsing `retry-after` header as seconds (allowing nonstandard floats). + retry_header = response_headers.get("retry-after") + try: + # note: the spec indicates that this should only ever be an integer + # but if someone sends a float there's no reason for us to not respect it + return float(retry_header) + except (TypeError, ValueError): + pass + + # Last, try parsing `retry-after` as a date. + retry_date_tuple = email.utils.parsedate_tz(retry_header) + if retry_date_tuple is None: + return None + + retry_date = email.utils.mktime_tz(retry_date_tuple) + return float(retry_date - time.time()) + + def _calculate_retry_timeout( + self, + remaining_retries: int, + options: FinalRequestOptions, + response_headers: Optional[httpx.Headers] = None, + ) -> float: + max_retries = options.get_max_retries(self.max_retries) + + # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. + retry_after = self._parse_retry_after_header(response_headers) + if retry_after is not None and 0 < retry_after <= 60: + return retry_after + + # Also cap retry count to 1000 to avoid any potential overflows with `pow` + nb_retries = min(max_retries - remaining_retries, 1000) + + # Apply exponential backoff, but not more than the max. + sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) + + # Apply some jitter, plus-or-minus half a second. + jitter = 1 - 0.25 * random() + timeout = sleep_seconds * jitter + return timeout if timeout >= 0 else 0 + + def _should_retry(self, response: httpx.Response) -> bool: + # Note: this is not a standard header + should_retry_header = response.headers.get("x-should-retry") + + # If the server explicitly says whether or not to retry, obey. + if should_retry_header == "true": + log.debug("Retrying as header `x-should-retry` is set to `true`") + return True + if should_retry_header == "false": + log.debug("Not retrying as header `x-should-retry` is set to `false`") + return False + + # Retry on request timeouts. + if response.status_code == 408: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry on lock timeouts. + if response.status_code == 409: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry on rate limits. + if response.status_code == 429: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry internal errors. + if response.status_code >= 500: + log.debug("Retrying due to status code %i", response.status_code) + return True + + log.debug("Not retrying") + return False + + def _idempotency_key(self) -> str: + return f"stainless-python-retry-{uuid.uuid4()}" + + +class _DefaultHttpxClient(httpx.Client): + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + super().__init__(**kwargs) + + +if TYPE_CHECKING: + DefaultHttpxClient = httpx.Client + """An alias to `httpx.Client` that provides the same defaults that this SDK + uses internally. + + This is useful because overriding the `http_client` with your own instance of + `httpx.Client` will result in httpx's defaults being used, not ours. + """ +else: + DefaultHttpxClient = _DefaultHttpxClient + + +class SyncHttpxClientWrapper(DefaultHttpxClient): + def __del__(self) -> None: + if self.is_closed: + return + + try: + self.close() + except Exception: + pass + + +class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]): + _client: httpx.Client + _default_stream_cls: type[Stream[Any]] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + http_client: httpx.Client | None = None, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + _strict_response_validation: bool, + ) -> None: + if not is_given(timeout): + # if the user passed in a custom http client with a non-default + # timeout set then we use that timeout. + # + # note: there is an edge case here where the user passes in a client + # where they've explicitly set the timeout to match the default timeout + # as this check is structural, meaning that we'll think they didn't + # pass in a timeout and will ignore it + if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: + timeout = http_client.timeout + else: + timeout = DEFAULT_TIMEOUT + + if http_client is not None and not isinstance(http_client, httpx.Client): # pyright: ignore[reportUnnecessaryIsInstance] + raise TypeError( + f"Invalid `http_client` argument; Expected an instance of `httpx.Client` but got {type(http_client)}" + ) + + super().__init__( + version=version, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + base_url=base_url, + max_retries=max_retries, + custom_query=custom_query, + custom_headers=custom_headers, + _strict_response_validation=_strict_response_validation, + ) + self._client = http_client or SyncHttpxClientWrapper( + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + ) + + def is_closed(self) -> bool: + return self._client.is_closed + + def close(self) -> None: + """Close the underlying HTTPX client. + + The client will *not* be usable after this. + """ + # If an error is thrown while constructing a client, self._client + # may not be present + if hasattr(self, "_client"): + self._client.close() + + def __enter__(self: _T) -> _T: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def _prepare_options( + self, + options: FinalRequestOptions, # noqa: ARG002 + ) -> FinalRequestOptions: + """Hook for mutating the given options""" + return options + + def _prepare_request( + self, + request: httpx.Request, # noqa: ARG002 + ) -> None: + """This method is used as a callback for mutating the `Request` object + after it has been constructed. + This is useful for cases where you want to add certain headers based off of + the request properties, e.g. `url`, `method` etc. + """ + return None + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[True], + stream_cls: Type[_StreamT], + ) -> _StreamT: ... + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: Type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + cast_to = self._maybe_override_cast_to(cast_to, options) + + # create a copy of the options we were given so that if the + # options are mutated later & we then retry, the retries are + # given the original options + input_options = model_copy(options) + if input_options.idempotency_key is None and input_options.method.lower() != "get": + # ensure the idempotency key is reused between requests + input_options.idempotency_key = self._idempotency_key() + + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) + + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = self._prepare_options(options) + + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + self._prepare_request(request) + + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth + + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + + log.debug("Sending HTTP Request: %s %s", request.method, request.url) + + response = None + try: + response = self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) + + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + err.response.close() + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue + + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + err.response.read() + + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None + + break + + assert response is not None, "could not resolve response (should never happen)" + return self._process_response( + cast_to=cast_to, + options=options, + response=response, + stream=stream, + stream_cls=stream_cls, + retries_taken=retries_taken, + ) + + def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = max_retries - retries_taken + if remaining_retries == 1: + log.debug("1 retry left") + else: + log.debug("%i retries left", remaining_retries) + + timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) + log.info("Retrying request to %s in %f seconds", options.url, timeout) + + time.sleep(timeout) + + def _process_response( + self, + *, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + response: httpx.Response, + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + retries_taken: int = 0, + ) -> ResponseT: + origin = get_origin(cast_to) or cast_to + + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): + if not issubclass(origin, APIResponse): + raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") + + response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) + return cast( + ResponseT, + response_cls( + raw=response, + client=self, + cast_to=extract_response_type(response_cls), + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ), + ) + + if cast_to == httpx.Response: + return cast(ResponseT, response) + + api_response = APIResponse( + raw=response, + client=self, + cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ) + if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): + return cast(ResponseT, api_response) + + return api_response.parse() + + def _request_api_list( + self, + model: Type[object], + page: Type[SyncPageT], + options: FinalRequestOptions, + ) -> SyncPageT: + def _parser(resp: SyncPageT) -> SyncPageT: + resp._set_private_attributes( + client=self, + model=model, + options=options, + ) + return resp + + options.post_parser = _parser + + return self.request(page, options, stream=False) + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_StreamT], + ) -> _StreamT: ... + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + opts = FinalRequestOptions.construct(method="get", url=path, **options) + # cast is required because mypy complains about returning Any even though + # it understands the type variables + return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: Literal[True], + stream_cls: type[_StreamT], + ) -> _StreamT: ... + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: bool, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + opts = FinalRequestOptions.construct( + method="post", url=path, json_data=body, files=to_httpx_files(files), **options + ) + return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) + + def patch( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + return self.request(cast_to, opts) + + def put( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + opts = FinalRequestOptions.construct( + method="put", url=path, json_data=body, files=to_httpx_files(files), **options + ) + return self.request(cast_to, opts) + + def delete( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) + return self.request(cast_to, opts) + + def get_api_list( + self, + path: str, + *, + model: Type[object], + page: Type[SyncPageT], + body: Body | None = None, + options: RequestOptions = {}, + method: str = "get", + ) -> SyncPageT: + opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) + return self._request_api_list(model, page, opts) + + +class _DefaultAsyncHttpxClient(httpx.AsyncClient): + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + super().__init__(**kwargs) + + +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + +if TYPE_CHECKING: + DefaultAsyncHttpxClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK + uses internally. + + This is useful because overriding the `http_client` with your own instance of + `httpx.AsyncClient` will result in httpx's defaults being used, not ours. + """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" +else: + DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient + + +class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): + def __del__(self) -> None: + if self.is_closed: + return + + try: + # TODO(someday): support non asyncio runtimes here + asyncio.get_running_loop().create_task(self.aclose()) + except Exception: + pass + + +class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]): + _client: httpx.AsyncClient + _default_stream_cls: type[AsyncStream[Any]] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + _strict_response_validation: bool, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + http_client: httpx.AsyncClient | None = None, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + ) -> None: + if not is_given(timeout): + # if the user passed in a custom http client with a non-default + # timeout set then we use that timeout. + # + # note: there is an edge case here where the user passes in a client + # where they've explicitly set the timeout to match the default timeout + # as this check is structural, meaning that we'll think they didn't + # pass in a timeout and will ignore it + if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: + timeout = http_client.timeout + else: + timeout = DEFAULT_TIMEOUT + + if http_client is not None and not isinstance(http_client, httpx.AsyncClient): # pyright: ignore[reportUnnecessaryIsInstance] + raise TypeError( + f"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` but got {type(http_client)}" + ) + + super().__init__( + version=version, + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + max_retries=max_retries, + custom_query=custom_query, + custom_headers=custom_headers, + _strict_response_validation=_strict_response_validation, + ) + self._client = http_client or AsyncHttpxClientWrapper( + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + ) + + def is_closed(self) -> bool: + return self._client.is_closed + + async def close(self) -> None: + """Close the underlying HTTPX client. + + The client will *not* be usable after this. + """ + await self._client.aclose() + + async def __aenter__(self: _T) -> _T: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.close() + + async def _prepare_options( + self, + options: FinalRequestOptions, # noqa: ARG002 + ) -> FinalRequestOptions: + """Hook for mutating the given options""" + return options + + async def _prepare_request( + self, + request: httpx.Request, # noqa: ARG002 + ) -> None: + """This method is used as a callback for mutating the `Request` object + after it has been constructed. + This is useful for cases where you want to add certain headers based off of + the request properties, e.g. `url`, `method` etc. + """ + return None + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + if self._platform is None: + # `get_platform` can make blocking IO calls so we + # execute it earlier while we are in an async context + self._platform = await asyncify(get_platform)() + + cast_to = self._maybe_override_cast_to(cast_to, options) + + # create a copy of the options we were given so that if the + # options are mutated later & we then retry, the retries are + # given the original options + input_options = model_copy(options) + if input_options.idempotency_key is None and input_options.method.lower() != "get": + # ensure the idempotency key is reused between requests + input_options.idempotency_key = self._idempotency_key() + + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) + + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = await self._prepare_options(options) + + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + await self._prepare_request(request) + + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth + + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + + log.debug("Sending HTTP Request: %s %s", request.method, request.url) + + response = None + try: + response = await self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) + + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + await err.response.aclose() + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue + + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + await err.response.aread() + + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None + + break + + assert response is not None, "could not resolve response (should never happen)" + return await self._process_response( + cast_to=cast_to, + options=options, + response=response, + stream=stream, + stream_cls=stream_cls, + retries_taken=retries_taken, + ) + + async def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = max_retries - retries_taken + if remaining_retries == 1: + log.debug("1 retry left") + else: + log.debug("%i retries left", remaining_retries) + + timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) + log.info("Retrying request to %s in %f seconds", options.url, timeout) + + await anyio.sleep(timeout) + + async def _process_response( + self, + *, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + response: httpx.Response, + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + retries_taken: int = 0, + ) -> ResponseT: + origin = get_origin(cast_to) or cast_to + + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): + if not issubclass(origin, AsyncAPIResponse): + raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") + + response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) + return cast( + "ResponseT", + response_cls( + raw=response, + client=self, + cast_to=extract_response_type(response_cls), + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ), + ) + + if cast_to == httpx.Response: + return cast(ResponseT, response) + + api_response = AsyncAPIResponse( + raw=response, + client=self, + cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ) + if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): + return cast(ResponseT, api_response) + + return await api_response.parse() + + def _request_api_list( + self, + model: Type[_T], + page: Type[AsyncPageT], + options: FinalRequestOptions, + ) -> AsyncPaginator[_T, AsyncPageT]: + return AsyncPaginator(client=self, options=options, page_cls=page, model=model) + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + opts = FinalRequestOptions.construct(method="get", url=path, **options) + return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + opts = FinalRequestOptions.construct( + method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options + ) + return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) + + async def patch( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + return await self.request(cast_to, opts) + + async def put( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + opts = FinalRequestOptions.construct( + method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options + ) + return await self.request(cast_to, opts) + + async def delete( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) + return await self.request(cast_to, opts) + + def get_api_list( + self, + path: str, + *, + model: Type[_T], + page: Type[AsyncPageT], + body: Body | None = None, + options: RequestOptions = {}, + method: str = "get", + ) -> AsyncPaginator[_T, AsyncPageT]: + opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) + return self._request_api_list(model, page, opts) + + +def make_request_options( + *, + query: Query | None = None, + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + idempotency_key: str | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + post_parser: PostParser | NotGiven = NOT_GIVEN, +) -> RequestOptions: + """Create a dict of type RequestOptions without keys of NotGiven values.""" + options: RequestOptions = {} + if extra_headers is not None: + options["headers"] = extra_headers + + if extra_body is not None: + options["extra_json"] = cast(AnyMapping, extra_body) + + if query is not None: + options["params"] = query + + if extra_query is not None: + options["params"] = {**options.get("params", {}), **extra_query} + + if not isinstance(timeout, NotGiven): + options["timeout"] = timeout + + if idempotency_key is not None: + options["idempotency_key"] = idempotency_key + + if is_given(post_parser): + # internal + options["post_parser"] = post_parser # type: ignore + + return options + + +class ForceMultipartDict(Dict[str, None]): + def __bool__(self) -> bool: + return True + + +class OtherPlatform: + def __init__(self, name: str) -> None: + self.name = name + + @override + def __str__(self) -> str: + return f"Other:{self.name}" + + +Platform = Union[ + OtherPlatform, + Literal[ + "MacOS", + "Linux", + "Windows", + "FreeBSD", + "OpenBSD", + "iOS", + "Android", + "Unknown", + ], +] + + +def get_platform() -> Platform: + try: + system = platform.system().lower() + platform_name = platform.platform().lower() + except Exception: + return "Unknown" + + if "iphone" in platform_name or "ipad" in platform_name: + # Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7 + # system is Darwin and platform_name is a string like: + # - Darwin-21.6.0-iPhone12,1-64bit + # - Darwin-21.6.0-iPad7,11-64bit + return "iOS" + + if system == "darwin": + return "MacOS" + + if system == "windows": + return "Windows" + + if "android" in platform_name: + # Tested using Pydroid 3 + # system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc' + return "Android" + + if system == "linux": + # https://distro.readthedocs.io/en/latest/#distro.id + distro_id = distro.id() + if distro_id == "freebsd": + return "FreeBSD" + + if distro_id == "openbsd": + return "OpenBSD" + + return "Linux" + + if platform_name: + return OtherPlatform(platform_name) + + return "Unknown" + + +@lru_cache(maxsize=None) +def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]: + return { + "X-Stainless-Lang": "python", + "X-Stainless-Package-Version": version, + "X-Stainless-OS": str(platform or get_platform()), + "X-Stainless-Arch": str(get_architecture()), + "X-Stainless-Runtime": get_python_runtime(), + "X-Stainless-Runtime-Version": get_python_version(), + } + + +class OtherArch: + def __init__(self, name: str) -> None: + self.name = name + + @override + def __str__(self) -> str: + return f"other:{self.name}" + + +Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]] + + +def get_python_runtime() -> str: + try: + return platform.python_implementation() + except Exception: + return "unknown" + + +def get_python_version() -> str: + try: + return platform.python_version() + except Exception: + return "unknown" + + +def get_architecture() -> Arch: + try: + machine = platform.machine().lower() + except Exception: + return "unknown" + + if machine in ("arm64", "aarch64"): + return "arm64" + + # TODO: untested + if machine == "arm": + return "arm" + + if machine == "x86_64": + return "x64" + + # TODO: untested + if sys.maxsize <= 2**32: + return "x32" + + if machine: + return OtherArch(machine) + + return "unknown" + + +def _merge_mappings( + obj1: Mapping[_T_co, Union[_T, Omit]], + obj2: Mapping[_T_co, Union[_T, Omit]], +) -> Dict[_T_co, _T]: + """Merge two mappings of the same type, removing any values that are instances of `Omit`. + + In cases with duplicate keys the second mapping takes precedence. + """ + merged = {**obj1, **obj2} + return {key: value for key, value in merged.items() if not isinstance(value, Omit)} diff --git a/src/gitpod/_client.py b/src/gitpod/_client.py new file mode 100644 index 0000000..dd0ccc2 --- /dev/null +++ b/src/gitpod/_client.py @@ -0,0 +1,495 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, Union, Mapping +from typing_extensions import Self, override + +import httpx + +from . import _exceptions +from ._qs import Querystring +from ._types import ( + NOT_GIVEN, + Omit, + Timeout, + NotGiven, + Transport, + ProxiesTypes, + RequestOptions, +) +from ._utils import is_given, get_async_library +from ._version import __version__ +from .resources import usage, events, groups, editors, secrets, accounts, gateways, identity +from ._streaming import Stream as Stream, AsyncStream as AsyncStream +from ._exceptions import GitpodError, APIStatusError +from ._base_client import ( + DEFAULT_MAX_RETRIES, + SyncAPIClient, + AsyncAPIClient, +) +from .resources.users import users +from .resources.runners import runners +from .resources.projects import projects +from .resources.environments import environments +from .resources.organizations import organizations + +__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Gitpod", "AsyncGitpod", "Client", "AsyncClient"] + + +class Gitpod(SyncAPIClient): + accounts: accounts.AccountsResource + editors: editors.EditorsResource + environments: environments.EnvironmentsResource + events: events.EventsResource + gateways: gateways.GatewaysResource + groups: groups.GroupsResource + identity: identity.IdentityResource + organizations: organizations.OrganizationsResource + projects: projects.ProjectsResource + runners: runners.RunnersResource + secrets: secrets.SecretsResource + usage: usage.UsageResource + users: users.UsersResource + with_raw_response: GitpodWithRawResponse + with_streaming_response: GitpodWithStreamedResponse + + # client options + bearer_token: str + + def __init__( + self, + *, + bearer_token: str | None = None, + base_url: str | httpx.URL | None = None, + timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + max_retries: int = DEFAULT_MAX_RETRIES, + default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + # Configure a custom httpx client. + # We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. + # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details. + http_client: httpx.Client | None = None, + # Enable or disable schema validation for data returned by the API. + # When enabled an error APIResponseValidationError is raised + # if the API responds with invalid data for the expected schema. + # + # This parameter may be removed or changed in the future. + # If you rely on this feature, please open a GitHub issue + # outlining your use-case to help us decide if it should be + # part of our public interface in the future. + _strict_response_validation: bool = False, + ) -> None: + """Construct a new synchronous Gitpod client instance. + + This automatically infers the `bearer_token` argument from the `GITPOD_API_KEY` environment variable if it is not provided. + """ + if bearer_token is None: + bearer_token = os.environ.get("GITPOD_API_KEY") + if bearer_token is None: + raise GitpodError( + "The bearer_token client option must be set either by passing bearer_token to the client or by setting the GITPOD_API_KEY environment variable" + ) + self.bearer_token = bearer_token + + if base_url is None: + base_url = os.environ.get("GITPOD_BASE_URL") + if base_url is None: + base_url = f"https://app.gitpod.io/api" + + super().__init__( + version=__version__, + base_url=base_url, + max_retries=max_retries, + timeout=timeout, + http_client=http_client, + custom_headers=default_headers, + custom_query=default_query, + _strict_response_validation=_strict_response_validation, + ) + + self.accounts = accounts.AccountsResource(self) + self.editors = editors.EditorsResource(self) + self.environments = environments.EnvironmentsResource(self) + self.events = events.EventsResource(self) + self.gateways = gateways.GatewaysResource(self) + self.groups = groups.GroupsResource(self) + self.identity = identity.IdentityResource(self) + self.organizations = organizations.OrganizationsResource(self) + self.projects = projects.ProjectsResource(self) + self.runners = runners.RunnersResource(self) + self.secrets = secrets.SecretsResource(self) + self.usage = usage.UsageResource(self) + self.users = users.UsersResource(self) + self.with_raw_response = GitpodWithRawResponse(self) + self.with_streaming_response = GitpodWithStreamedResponse(self) + + @property + @override + def qs(self) -> Querystring: + return Querystring(array_format="comma") + + @property + @override + def auth_headers(self) -> dict[str, str]: + bearer_token = self.bearer_token + return {"Authorization": f"Bearer {bearer_token}"} + + @property + @override + def default_headers(self) -> dict[str, str | Omit]: + return { + **super().default_headers, + "X-Stainless-Async": "false", + **self._custom_headers, + } + + def copy( + self, + *, + bearer_token: str | None = None, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + http_client: httpx.Client | None = None, + max_retries: int | NotGiven = NOT_GIVEN, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: + """ + Create a new client instance re-using the same options given to the current client with optional overriding. + """ + if default_headers is not None and set_default_headers is not None: + raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") + + if default_query is not None and set_default_query is not None: + raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") + + headers = self._custom_headers + if default_headers is not None: + headers = {**headers, **default_headers} + elif set_default_headers is not None: + headers = set_default_headers + + params = self._custom_query + if default_query is not None: + params = {**params, **default_query} + elif set_default_query is not None: + params = set_default_query + + http_client = http_client or self._client + return self.__class__( + bearer_token=bearer_token or self.bearer_token, + base_url=base_url or self.base_url, + timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, + http_client=http_client, + max_retries=max_retries if is_given(max_retries) else self.max_retries, + default_headers=headers, + default_query=params, + **_extra_kwargs, + ) + + # Alias for `copy` for nicer inline usage, e.g. + # client.with_options(timeout=10).foo.create(...) + with_options = copy + + @override + def _make_status_error( + self, + err_msg: str, + *, + body: object, + response: httpx.Response, + ) -> APIStatusError: + if response.status_code == 400: + return _exceptions.BadRequestError(err_msg, response=response, body=body) + + if response.status_code == 401: + return _exceptions.AuthenticationError(err_msg, response=response, body=body) + + if response.status_code == 403: + return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) + + if response.status_code == 404: + return _exceptions.NotFoundError(err_msg, response=response, body=body) + + if response.status_code == 409: + return _exceptions.ConflictError(err_msg, response=response, body=body) + + if response.status_code == 422: + return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) + + if response.status_code == 429: + return _exceptions.RateLimitError(err_msg, response=response, body=body) + + if response.status_code >= 500: + return _exceptions.InternalServerError(err_msg, response=response, body=body) + return APIStatusError(err_msg, response=response, body=body) + + +class AsyncGitpod(AsyncAPIClient): + accounts: accounts.AsyncAccountsResource + editors: editors.AsyncEditorsResource + environments: environments.AsyncEnvironmentsResource + events: events.AsyncEventsResource + gateways: gateways.AsyncGatewaysResource + groups: groups.AsyncGroupsResource + identity: identity.AsyncIdentityResource + organizations: organizations.AsyncOrganizationsResource + projects: projects.AsyncProjectsResource + runners: runners.AsyncRunnersResource + secrets: secrets.AsyncSecretsResource + usage: usage.AsyncUsageResource + users: users.AsyncUsersResource + with_raw_response: AsyncGitpodWithRawResponse + with_streaming_response: AsyncGitpodWithStreamedResponse + + # client options + bearer_token: str + + def __init__( + self, + *, + bearer_token: str | None = None, + base_url: str | httpx.URL | None = None, + timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + max_retries: int = DEFAULT_MAX_RETRIES, + default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + # Configure a custom httpx client. + # We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. + # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details. + http_client: httpx.AsyncClient | None = None, + # Enable or disable schema validation for data returned by the API. + # When enabled an error APIResponseValidationError is raised + # if the API responds with invalid data for the expected schema. + # + # This parameter may be removed or changed in the future. + # If you rely on this feature, please open a GitHub issue + # outlining your use-case to help us decide if it should be + # part of our public interface in the future. + _strict_response_validation: bool = False, + ) -> None: + """Construct a new async AsyncGitpod client instance. + + This automatically infers the `bearer_token` argument from the `GITPOD_API_KEY` environment variable if it is not provided. + """ + if bearer_token is None: + bearer_token = os.environ.get("GITPOD_API_KEY") + if bearer_token is None: + raise GitpodError( + "The bearer_token client option must be set either by passing bearer_token to the client or by setting the GITPOD_API_KEY environment variable" + ) + self.bearer_token = bearer_token + + if base_url is None: + base_url = os.environ.get("GITPOD_BASE_URL") + if base_url is None: + base_url = f"https://app.gitpod.io/api" + + super().__init__( + version=__version__, + base_url=base_url, + max_retries=max_retries, + timeout=timeout, + http_client=http_client, + custom_headers=default_headers, + custom_query=default_query, + _strict_response_validation=_strict_response_validation, + ) + + self.accounts = accounts.AsyncAccountsResource(self) + self.editors = editors.AsyncEditorsResource(self) + self.environments = environments.AsyncEnvironmentsResource(self) + self.events = events.AsyncEventsResource(self) + self.gateways = gateways.AsyncGatewaysResource(self) + self.groups = groups.AsyncGroupsResource(self) + self.identity = identity.AsyncIdentityResource(self) + self.organizations = organizations.AsyncOrganizationsResource(self) + self.projects = projects.AsyncProjectsResource(self) + self.runners = runners.AsyncRunnersResource(self) + self.secrets = secrets.AsyncSecretsResource(self) + self.usage = usage.AsyncUsageResource(self) + self.users = users.AsyncUsersResource(self) + self.with_raw_response = AsyncGitpodWithRawResponse(self) + self.with_streaming_response = AsyncGitpodWithStreamedResponse(self) + + @property + @override + def qs(self) -> Querystring: + return Querystring(array_format="comma") + + @property + @override + def auth_headers(self) -> dict[str, str]: + bearer_token = self.bearer_token + return {"Authorization": f"Bearer {bearer_token}"} + + @property + @override + def default_headers(self) -> dict[str, str | Omit]: + return { + **super().default_headers, + "X-Stainless-Async": f"async:{get_async_library()}", + **self._custom_headers, + } + + def copy( + self, + *, + bearer_token: str | None = None, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + http_client: httpx.AsyncClient | None = None, + max_retries: int | NotGiven = NOT_GIVEN, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: + """ + Create a new client instance re-using the same options given to the current client with optional overriding. + """ + if default_headers is not None and set_default_headers is not None: + raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") + + if default_query is not None and set_default_query is not None: + raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") + + headers = self._custom_headers + if default_headers is not None: + headers = {**headers, **default_headers} + elif set_default_headers is not None: + headers = set_default_headers + + params = self._custom_query + if default_query is not None: + params = {**params, **default_query} + elif set_default_query is not None: + params = set_default_query + + http_client = http_client or self._client + return self.__class__( + bearer_token=bearer_token or self.bearer_token, + base_url=base_url or self.base_url, + timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, + http_client=http_client, + max_retries=max_retries if is_given(max_retries) else self.max_retries, + default_headers=headers, + default_query=params, + **_extra_kwargs, + ) + + # Alias for `copy` for nicer inline usage, e.g. + # client.with_options(timeout=10).foo.create(...) + with_options = copy + + @override + def _make_status_error( + self, + err_msg: str, + *, + body: object, + response: httpx.Response, + ) -> APIStatusError: + if response.status_code == 400: + return _exceptions.BadRequestError(err_msg, response=response, body=body) + + if response.status_code == 401: + return _exceptions.AuthenticationError(err_msg, response=response, body=body) + + if response.status_code == 403: + return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) + + if response.status_code == 404: + return _exceptions.NotFoundError(err_msg, response=response, body=body) + + if response.status_code == 409: + return _exceptions.ConflictError(err_msg, response=response, body=body) + + if response.status_code == 422: + return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) + + if response.status_code == 429: + return _exceptions.RateLimitError(err_msg, response=response, body=body) + + if response.status_code >= 500: + return _exceptions.InternalServerError(err_msg, response=response, body=body) + return APIStatusError(err_msg, response=response, body=body) + + +class GitpodWithRawResponse: + def __init__(self, client: Gitpod) -> None: + self.accounts = accounts.AccountsResourceWithRawResponse(client.accounts) + self.editors = editors.EditorsResourceWithRawResponse(client.editors) + self.environments = environments.EnvironmentsResourceWithRawResponse(client.environments) + self.events = events.EventsResourceWithRawResponse(client.events) + self.gateways = gateways.GatewaysResourceWithRawResponse(client.gateways) + self.groups = groups.GroupsResourceWithRawResponse(client.groups) + self.identity = identity.IdentityResourceWithRawResponse(client.identity) + self.organizations = organizations.OrganizationsResourceWithRawResponse(client.organizations) + self.projects = projects.ProjectsResourceWithRawResponse(client.projects) + self.runners = runners.RunnersResourceWithRawResponse(client.runners) + self.secrets = secrets.SecretsResourceWithRawResponse(client.secrets) + self.usage = usage.UsageResourceWithRawResponse(client.usage) + self.users = users.UsersResourceWithRawResponse(client.users) + + +class AsyncGitpodWithRawResponse: + def __init__(self, client: AsyncGitpod) -> None: + self.accounts = accounts.AsyncAccountsResourceWithRawResponse(client.accounts) + self.editors = editors.AsyncEditorsResourceWithRawResponse(client.editors) + self.environments = environments.AsyncEnvironmentsResourceWithRawResponse(client.environments) + self.events = events.AsyncEventsResourceWithRawResponse(client.events) + self.gateways = gateways.AsyncGatewaysResourceWithRawResponse(client.gateways) + self.groups = groups.AsyncGroupsResourceWithRawResponse(client.groups) + self.identity = identity.AsyncIdentityResourceWithRawResponse(client.identity) + self.organizations = organizations.AsyncOrganizationsResourceWithRawResponse(client.organizations) + self.projects = projects.AsyncProjectsResourceWithRawResponse(client.projects) + self.runners = runners.AsyncRunnersResourceWithRawResponse(client.runners) + self.secrets = secrets.AsyncSecretsResourceWithRawResponse(client.secrets) + self.usage = usage.AsyncUsageResourceWithRawResponse(client.usage) + self.users = users.AsyncUsersResourceWithRawResponse(client.users) + + +class GitpodWithStreamedResponse: + def __init__(self, client: Gitpod) -> None: + self.accounts = accounts.AccountsResourceWithStreamingResponse(client.accounts) + self.editors = editors.EditorsResourceWithStreamingResponse(client.editors) + self.environments = environments.EnvironmentsResourceWithStreamingResponse(client.environments) + self.events = events.EventsResourceWithStreamingResponse(client.events) + self.gateways = gateways.GatewaysResourceWithStreamingResponse(client.gateways) + self.groups = groups.GroupsResourceWithStreamingResponse(client.groups) + self.identity = identity.IdentityResourceWithStreamingResponse(client.identity) + self.organizations = organizations.OrganizationsResourceWithStreamingResponse(client.organizations) + self.projects = projects.ProjectsResourceWithStreamingResponse(client.projects) + self.runners = runners.RunnersResourceWithStreamingResponse(client.runners) + self.secrets = secrets.SecretsResourceWithStreamingResponse(client.secrets) + self.usage = usage.UsageResourceWithStreamingResponse(client.usage) + self.users = users.UsersResourceWithStreamingResponse(client.users) + + +class AsyncGitpodWithStreamedResponse: + def __init__(self, client: AsyncGitpod) -> None: + self.accounts = accounts.AsyncAccountsResourceWithStreamingResponse(client.accounts) + self.editors = editors.AsyncEditorsResourceWithStreamingResponse(client.editors) + self.environments = environments.AsyncEnvironmentsResourceWithStreamingResponse(client.environments) + self.events = events.AsyncEventsResourceWithStreamingResponse(client.events) + self.gateways = gateways.AsyncGatewaysResourceWithStreamingResponse(client.gateways) + self.groups = groups.AsyncGroupsResourceWithStreamingResponse(client.groups) + self.identity = identity.AsyncIdentityResourceWithStreamingResponse(client.identity) + self.organizations = organizations.AsyncOrganizationsResourceWithStreamingResponse(client.organizations) + self.projects = projects.AsyncProjectsResourceWithStreamingResponse(client.projects) + self.runners = runners.AsyncRunnersResourceWithStreamingResponse(client.runners) + self.secrets = secrets.AsyncSecretsResourceWithStreamingResponse(client.secrets) + self.usage = usage.AsyncUsageResourceWithStreamingResponse(client.usage) + self.users = users.AsyncUsersResourceWithStreamingResponse(client.users) + + +Client = Gitpod + +AsyncClient = AsyncGitpod diff --git a/src/gitpod/_compat.py b/src/gitpod/_compat.py new file mode 100644 index 0000000..92d9ee6 --- /dev/null +++ b/src/gitpod/_compat.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload +from datetime import date, datetime +from typing_extensions import Self, Literal + +import pydantic +from pydantic.fields import FieldInfo + +from ._types import IncEx, StrBytesIntFloat + +_T = TypeVar("_T") +_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) + +# --------------- Pydantic v2 compatibility --------------- + +# Pyright incorrectly reports some of our functions as overriding a method when they don't +# pyright: reportIncompatibleMethodOverride=false + +PYDANTIC_V2 = pydantic.VERSION.startswith("2.") + +# v1 re-exports +if TYPE_CHECKING: + + def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 + ... + + def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 + ... + + def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 + ... + + def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 + ... + + def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 + ... + + def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 + ... + + def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 + ... + +else: + if PYDANTIC_V2: + from pydantic.v1.typing import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, + ) + from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + else: + from pydantic.typing import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, + ) + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + + +# refactored config +if TYPE_CHECKING: + from pydantic import ConfigDict as ConfigDict +else: + if PYDANTIC_V2: + from pydantic import ConfigDict + else: + # TODO: provide an error message here? + ConfigDict = None + + +# renamed methods / properties +def parse_obj(model: type[_ModelT], value: object) -> _ModelT: + if PYDANTIC_V2: + return model.model_validate(value) + else: + return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + + +def field_is_required(field: FieldInfo) -> bool: + if PYDANTIC_V2: + return field.is_required() + return field.required # type: ignore + + +def field_get_default(field: FieldInfo) -> Any: + value = field.get_default() + if PYDANTIC_V2: + from pydantic_core import PydanticUndefined + + if value == PydanticUndefined: + return None + return value + return value + + +def field_outer_type(field: FieldInfo) -> Any: + if PYDANTIC_V2: + return field.annotation + return field.outer_type_ # type: ignore + + +def get_model_config(model: type[pydantic.BaseModel]) -> Any: + if PYDANTIC_V2: + return model.model_config + return model.__config__ # type: ignore + + +def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: + if PYDANTIC_V2: + return model.model_fields + return model.__fields__ # type: ignore + + +def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: + if PYDANTIC_V2: + return model.model_copy(deep=deep) + return model.copy(deep=deep) # type: ignore + + +def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: + if PYDANTIC_V2: + return model.model_dump_json(indent=indent) + return model.json(indent=indent) # type: ignore + + +def model_dump( + model: pydantic.BaseModel, + *, + exclude: IncEx | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + warnings: bool = True, + mode: Literal["json", "python"] = "python", +) -> dict[str, Any]: + if PYDANTIC_V2 or hasattr(model, "model_dump"): + return model.model_dump( + mode=mode, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + # warnings are not supported in Pydantic v1 + warnings=warnings if PYDANTIC_V2 else True, + ) + return cast( + "dict[str, Any]", + model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + ), + ) + + +def model_parse(model: type[_ModelT], data: Any) -> _ModelT: + if PYDANTIC_V2: + return model.model_validate(data) + return model.parse_obj(data) # pyright: ignore[reportDeprecated] + + +# generic models +if TYPE_CHECKING: + + class GenericModel(pydantic.BaseModel): ... + +else: + if PYDANTIC_V2: + # there no longer needs to be a distinction in v2 but + # we still have to create our own subclass to avoid + # inconsistent MRO ordering errors + class GenericModel(pydantic.BaseModel): ... + + else: + import pydantic.generics + + class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... + + +# cached properties +if TYPE_CHECKING: + cached_property = property + + # we define a separate type (copied from typeshed) + # that represents that `cached_property` is `set`able + # at runtime, which differs from `@property`. + # + # this is a separate type as editors likely special case + # `@property` and we don't want to cause issues just to have + # more helpful internal types. + + class typed_cached_property(Generic[_T]): + func: Callable[[Any], _T] + attrname: str | None + + def __init__(self, func: Callable[[Any], _T]) -> None: ... + + @overload + def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ... + + @overload + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ... + + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self: + raise NotImplementedError() + + def __set_name__(self, owner: type[Any], name: str) -> None: ... + + # __set__ is not defined at runtime, but @cached_property is designed to be settable + def __set__(self, instance: object, value: _T) -> None: ... +else: + from functools import cached_property as cached_property + + typed_cached_property = cached_property diff --git a/src/gitpod/_constants.py b/src/gitpod/_constants.py new file mode 100644 index 0000000..6ddf2c7 --- /dev/null +++ b/src/gitpod/_constants.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import httpx + +RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response" +OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" + +# default timeout is 1 minute +DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0) +DEFAULT_MAX_RETRIES = 2 +DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) + +INITIAL_RETRY_DELAY = 0.5 +MAX_RETRY_DELAY = 8.0 diff --git a/src/gitpod/_decoders/jsonl.py b/src/gitpod/_decoders/jsonl.py new file mode 100644 index 0000000..ac5ac74 --- /dev/null +++ b/src/gitpod/_decoders/jsonl.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +import json +from typing_extensions import Generic, TypeVar, Iterator, AsyncIterator + +import httpx + +from .._models import construct_type_unchecked + +_T = TypeVar("_T") + + +class JSONLDecoder(Generic[_T]): + """A decoder for [JSON Lines](https://jsonlines.org) format. + + This class provides an iterator over a byte-iterator that parses each JSON Line + into a given type. + """ + + http_response: httpx.Response + """The HTTP response this decoder was constructed from""" + + def __init__( + self, + *, + raw_iterator: Iterator[bytes], + line_type: type[_T], + http_response: httpx.Response, + ) -> None: + super().__init__() + self.http_response = http_response + self._raw_iterator = raw_iterator + self._line_type = line_type + self._iterator = self.__decode__() + + def close(self) -> None: + """Close the response body stream. + + This is called automatically if you consume the entire stream. + """ + self.http_response.close() + + def __decode__(self) -> Iterator[_T]: + buf = b"" + for chunk in self._raw_iterator: + for line in chunk.splitlines(keepends=True): + buf += line + if buf.endswith((b"\r", b"\n", b"\r\n")): + yield construct_type_unchecked( + value=json.loads(buf), + type_=self._line_type, + ) + buf = b"" + + # flush + if buf: + yield construct_type_unchecked( + value=json.loads(buf), + type_=self._line_type, + ) + + def __next__(self) -> _T: + return self._iterator.__next__() + + def __iter__(self) -> Iterator[_T]: + for item in self._iterator: + yield item + + +class AsyncJSONLDecoder(Generic[_T]): + """A decoder for [JSON Lines](https://jsonlines.org) format. + + This class provides an async iterator over a byte-iterator that parses each JSON Line + into a given type. + """ + + http_response: httpx.Response + + def __init__( + self, + *, + raw_iterator: AsyncIterator[bytes], + line_type: type[_T], + http_response: httpx.Response, + ) -> None: + super().__init__() + self.http_response = http_response + self._raw_iterator = raw_iterator + self._line_type = line_type + self._iterator = self.__decode__() + + async def close(self) -> None: + """Close the response body stream. + + This is called automatically if you consume the entire stream. + """ + await self.http_response.aclose() + + async def __decode__(self) -> AsyncIterator[_T]: + buf = b"" + async for chunk in self._raw_iterator: + for line in chunk.splitlines(keepends=True): + buf += line + if buf.endswith((b"\r", b"\n", b"\r\n")): + yield construct_type_unchecked( + value=json.loads(buf), + type_=self._line_type, + ) + buf = b"" + + # flush + if buf: + yield construct_type_unchecked( + value=json.loads(buf), + type_=self._line_type, + ) + + async def __anext__(self) -> _T: + return await self._iterator.__anext__() + + async def __aiter__(self) -> AsyncIterator[_T]: + async for item in self._iterator: + yield item diff --git a/src/gitpod/_exceptions.py b/src/gitpod/_exceptions.py new file mode 100644 index 0000000..bb138a9 --- /dev/null +++ b/src/gitpod/_exceptions.py @@ -0,0 +1,124 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, Optional, cast +from typing_extensions import Literal + +import httpx + +from ._utils import is_dict +from ._models import construct_type +from .types.shared.error_code import ErrorCode + +__all__ = [ + "BadRequestError", + "AuthenticationError", + "PermissionDeniedError", + "NotFoundError", + "ConflictError", + "UnprocessableEntityError", + "RateLimitError", + "InternalServerError", +] + + +class GitpodError(Exception): + pass + + +class APIError(GitpodError): + message: str + request: httpx.Request + + body: object | None + """The API response body. + + If the API responded with a valid JSON structure then this property will be the + decoded result. + + If it isn't a valid JSON structure then this will be the raw response. + + If there was no response associated with this error then it will be `None`. + """ + + code: Optional[ErrorCode] = None + """ + The status code, which should be an enum value of + [google.rpc.Code][google.rpc.Code]. + """ + + def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: + super().__init__(message) + self.request = request + self.message = message + self.body = body + + if is_dict(body): + self.code = cast(Any, construct_type(type_=Optional[ErrorCode], value=body.get("code"))) + else: + self.code = None + + +class APIResponseValidationError(APIError): + response: httpx.Response + status_code: int + + def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None: + super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body) + self.response = response + self.status_code = response.status_code + + +class APIStatusError(APIError): + """Raised when an API response has a status code of 4xx or 5xx.""" + + response: httpx.Response + status_code: int + + def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None: + super().__init__(message, response.request, body=body) + self.response = response + self.status_code = response.status_code + + +class APIConnectionError(APIError): + def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None: + super().__init__(message, request, body=None) + + +class APITimeoutError(APIConnectionError): + def __init__(self, request: httpx.Request) -> None: + super().__init__(message="Request timed out.", request=request) + + +class BadRequestError(APIStatusError): + status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride] + + +class AuthenticationError(APIStatusError): + status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride] + + +class PermissionDeniedError(APIStatusError): + status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride] + + +class NotFoundError(APIStatusError): + status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride] + + +class ConflictError(APIStatusError): + status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride] + + +class UnprocessableEntityError(APIStatusError): + status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride] + + +class RateLimitError(APIStatusError): + status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride] + + +class InternalServerError(APIStatusError): + pass diff --git a/src/gitpod/_files.py b/src/gitpod/_files.py new file mode 100644 index 0000000..715cc20 --- /dev/null +++ b/src/gitpod/_files.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +import io +import os +import pathlib +from typing import overload +from typing_extensions import TypeGuard + +import anyio + +from ._types import ( + FileTypes, + FileContent, + RequestFiles, + HttpxFileTypes, + Base64FileInput, + HttpxFileContent, + HttpxRequestFiles, +) +from ._utils import is_tuple_t, is_mapping_t, is_sequence_t + + +def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: + return isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) + + +def is_file_content(obj: object) -> TypeGuard[FileContent]: + return ( + isinstance(obj, bytes) or isinstance(obj, tuple) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) + ) + + +def assert_is_file_content(obj: object, *, key: str | None = None) -> None: + if not is_file_content(obj): + prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" + raise RuntimeError( + f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead." + ) from None + + +@overload +def to_httpx_files(files: None) -> None: ... + + +@overload +def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... + + +def to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: + if files is None: + return None + + if is_mapping_t(files): + files = {key: _transform_file(file) for key, file in files.items()} + elif is_sequence_t(files): + files = [(key, _transform_file(file)) for key, file in files] + else: + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") + + return files + + +def _transform_file(file: FileTypes) -> HttpxFileTypes: + if is_file_content(file): + if isinstance(file, os.PathLike): + path = pathlib.Path(file) + return (path.name, path.read_bytes()) + + return file + + if is_tuple_t(file): + return (file[0], _read_file_content(file[1]), *file[2:]) + + raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") + + +def _read_file_content(file: FileContent) -> HttpxFileContent: + if isinstance(file, os.PathLike): + return pathlib.Path(file).read_bytes() + return file + + +@overload +async def async_to_httpx_files(files: None) -> None: ... + + +@overload +async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... + + +async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: + if files is None: + return None + + if is_mapping_t(files): + files = {key: await _async_transform_file(file) for key, file in files.items()} + elif is_sequence_t(files): + files = [(key, await _async_transform_file(file)) for key, file in files] + else: + raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") + + return files + + +async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: + if is_file_content(file): + if isinstance(file, os.PathLike): + path = anyio.Path(file) + return (path.name, await path.read_bytes()) + + return file + + if is_tuple_t(file): + return (file[0], await _async_read_file_content(file[1]), *file[2:]) + + raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") + + +async def _async_read_file_content(file: FileContent) -> HttpxFileContent: + if isinstance(file, os.PathLike): + return await anyio.Path(file).read_bytes() + + return file diff --git a/src/gitpod/_models.py b/src/gitpod/_models.py new file mode 100644 index 0000000..528d568 --- /dev/null +++ b/src/gitpod/_models.py @@ -0,0 +1,808 @@ +from __future__ import annotations + +import os +import inspect +from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast +from datetime import date, datetime +from typing_extensions import ( + List, + Unpack, + Literal, + ClassVar, + Protocol, + Required, + ParamSpec, + TypedDict, + TypeGuard, + final, + override, + runtime_checkable, +) + +import pydantic +from pydantic.fields import FieldInfo + +from ._types import ( + Body, + IncEx, + Query, + ModelT, + Headers, + Timeout, + NotGiven, + AnyMapping, + HttpxRequestFiles, +) +from ._utils import ( + PropertyInfo, + is_list, + is_given, + json_safe, + lru_cache, + is_mapping, + parse_date, + coerce_boolean, + parse_datetime, + strip_not_given, + extract_type_arg, + is_annotated_type, + is_type_alias_type, + strip_annotated_type, +) +from ._compat import ( + PYDANTIC_V2, + ConfigDict, + GenericModel as BaseGenericModel, + get_args, + is_union, + parse_obj, + get_origin, + is_literal_type, + get_model_config, + get_model_fields, + field_get_default, +) +from ._constants import RAW_RESPONSE_HEADER + +if TYPE_CHECKING: + from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema + +__all__ = ["BaseModel", "GenericModel"] + +_T = TypeVar("_T") +_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel") + +P = ParamSpec("P") + + +@runtime_checkable +class _ConfigProtocol(Protocol): + allow_population_by_field_name: bool + + +class BaseModel(pydantic.BaseModel): + if PYDANTIC_V2: + model_config: ClassVar[ConfigDict] = ConfigDict( + extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) + ) + else: + + @property + @override + def model_fields_set(self) -> set[str]: + # a forwards-compat shim for pydantic v2 + return self.__fields_set__ # type: ignore + + class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] + extra: Any = pydantic.Extra.allow # type: ignore + + def to_dict( + self, + *, + mode: Literal["json", "python"] = "python", + use_api_names: bool = True, + exclude_unset: bool = True, + exclude_defaults: bool = False, + exclude_none: bool = False, + warnings: bool = True, + ) -> dict[str, object]: + """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + By default, fields that were not set by the API will not be included, + and keys will match the API response, *not* the property names from the model. + + For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, + the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). + + Args: + mode: + If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`. + If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)` + + use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value from the output. + exclude_none: Whether to exclude fields that have a value of `None` from the output. + warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2. + """ + return self.model_dump( + mode=mode, + by_alias=use_api_names, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + warnings=warnings, + ) + + def to_json( + self, + *, + indent: int | None = 2, + use_api_names: bool = True, + exclude_unset: bool = True, + exclude_defaults: bool = False, + exclude_none: bool = False, + warnings: bool = True, + ) -> str: + """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation). + + By default, fields that were not set by the API will not be included, + and keys will match the API response, *not* the property names from the model. + + For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, + the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). + + Args: + indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2` + use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that have the default value. + exclude_none: Whether to exclude fields that have a value of `None`. + warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2. + """ + return self.model_dump_json( + indent=indent, + by_alias=use_api_names, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + warnings=warnings, + ) + + @override + def __str__(self) -> str: + # mypy complains about an invalid self arg + return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] + + # Override the 'construct' method in a way that supports recursive parsing without validation. + # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. + @classmethod + @override + def construct( # pyright: ignore[reportIncompatibleMethodOverride] + __cls: Type[ModelT], + _fields_set: set[str] | None = None, + **values: object, + ) -> ModelT: + m = __cls.__new__(__cls) + fields_values: dict[str, object] = {} + + config = get_model_config(__cls) + populate_by_name = ( + config.allow_population_by_field_name + if isinstance(config, _ConfigProtocol) + else config.get("populate_by_name") + ) + + if _fields_set is None: + _fields_set = set() + + model_fields = get_model_fields(__cls) + for name, field in model_fields.items(): + key = field.alias + if key is None or (key not in values and populate_by_name): + key = name + + if key in values: + fields_values[name] = _construct_field(value=values[key], field=field, key=key) + _fields_set.add(name) + else: + fields_values[name] = field_get_default(field) + + _extra = {} + for key, value in values.items(): + if key not in model_fields: + if PYDANTIC_V2: + _extra[key] = value + else: + _fields_set.add(key) + fields_values[key] = value + + object.__setattr__(m, "__dict__", fields_values) + + if PYDANTIC_V2: + # these properties are copied from Pydantic's `model_construct()` method + object.__setattr__(m, "__pydantic_private__", None) + object.__setattr__(m, "__pydantic_extra__", _extra) + object.__setattr__(m, "__pydantic_fields_set__", _fields_set) + else: + # init_private_attributes() does not exist in v2 + m._init_private_attributes() # type: ignore + + # copied from Pydantic v1's `construct()` method + object.__setattr__(m, "__fields_set__", _fields_set) + + return m + + if not TYPE_CHECKING: + # type checkers incorrectly complain about this assignment + # because the type signatures are technically different + # although not in practice + model_construct = construct + + if not PYDANTIC_V2: + # we define aliases for some of the new pydantic v2 methods so + # that we can just document these methods without having to specify + # a specific pydantic version as some users may not know which + # pydantic version they are currently using + + @override + def model_dump( + self, + *, + mode: Literal["json", "python"] | str = "python", + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + round_trip: bool = False, + warnings: bool | Literal["none", "warn", "error"] = True, + context: dict[str, Any] | None = None, + serialize_as_any: bool = False, + ) -> dict[str, Any]: + """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump + + Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + Args: + mode: The mode in which `to_python` should run. + If mode is 'json', the dictionary will only contain JSON serializable types. + If mode is 'python', the dictionary may contain any Python objects. + include: A list of fields to include in the output. + exclude: A list of fields to exclude from the output. + by_alias: Whether to use the field's alias in the dictionary key if defined. + exclude_unset: Whether to exclude fields that are unset or None from the output. + exclude_defaults: Whether to exclude fields that are set to their default value from the output. + exclude_none: Whether to exclude fields that have a value of `None` from the output. + round_trip: Whether to enable serialization and deserialization round-trip support. + warnings: Whether to log warnings when invalid fields are encountered. + + Returns: + A dictionary representation of the model. + """ + if mode not in {"json", "python"}: + raise ValueError("mode must be either 'json' or 'python'") + if round_trip != False: + raise ValueError("round_trip is only supported in Pydantic v2") + if warnings != True: + raise ValueError("warnings is only supported in Pydantic v2") + if context is not None: + raise ValueError("context is only supported in Pydantic v2") + if serialize_as_any != False: + raise ValueError("serialize_as_any is only supported in Pydantic v2") + dumped = super().dict( # pyright: ignore[reportDeprecated] + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped + + @override + def model_dump_json( + self, + *, + indent: int | None = None, + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + round_trip: bool = False, + warnings: bool | Literal["none", "warn", "error"] = True, + context: dict[str, Any] | None = None, + serialize_as_any: bool = False, + ) -> str: + """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json + + Generates a JSON representation of the model using Pydantic's `to_json` method. + + Args: + indent: Indentation to use in the JSON output. If None is passed, the output will be compact. + include: Field(s) to include in the JSON output. Can take either a string or set of strings. + exclude: Field(s) to exclude from the JSON output. Can take either a string or set of strings. + by_alias: Whether to serialize using field aliases. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that have the default value. + exclude_none: Whether to exclude fields that have a value of `None`. + round_trip: Whether to use serialization/deserialization between JSON and class instance. + warnings: Whether to show any warnings that occurred during serialization. + + Returns: + A JSON string representation of the model. + """ + if round_trip != False: + raise ValueError("round_trip is only supported in Pydantic v2") + if warnings != True: + raise ValueError("warnings is only supported in Pydantic v2") + if context is not None: + raise ValueError("context is only supported in Pydantic v2") + if serialize_as_any != False: + raise ValueError("serialize_as_any is only supported in Pydantic v2") + return super().json( # type: ignore[reportDeprecated] + indent=indent, + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + +def _construct_field(value: object, field: FieldInfo, key: str) -> object: + if value is None: + return field_get_default(field) + + if PYDANTIC_V2: + type_ = field.annotation + else: + type_ = cast(type, field.outer_type_) # type: ignore + + if type_ is None: + raise RuntimeError(f"Unexpected field type is None for {key}") + + return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) + + +def is_basemodel(type_: type) -> bool: + """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" + if is_union(type_): + for variant in get_args(type_): + if is_basemodel(variant): + return True + + return False + + return is_basemodel_type(type_) + + +def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]: + origin = get_origin(type_) or type_ + if not inspect.isclass(origin): + return False + return issubclass(origin, BaseModel) or issubclass(origin, GenericModel) + + +def build( + base_model_cls: Callable[P, _BaseModelT], + *args: P.args, + **kwargs: P.kwargs, +) -> _BaseModelT: + """Construct a BaseModel class without validation. + + This is useful for cases where you need to instantiate a `BaseModel` + from an API response as this provides type-safe params which isn't supported + by helpers like `construct_type()`. + + ```py + build(MyModel, my_field_a="foo", my_field_b=123) + ``` + """ + if args: + raise TypeError( + "Received positional arguments which are not supported; Keyword arguments must be used instead", + ) + + return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs)) + + +def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: + """Loose coercion to the expected type with construction of nested values. + + Note: the returned value from this function is not guaranteed to match the + given type. + """ + return cast(_T, construct_type(value=value, type_=type_)) + + +def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: + """Loose coercion to the expected type with construction of nested values. + + If the given value does not match the expected type then it is returned as-is. + """ + + # store a reference to the original type we were given before we extract any inner + # types so that we can properly resolve forward references in `TypeAliasType` annotations + original_type = None + + # we allow `object` as the input type because otherwise, passing things like + # `Literal['value']` will be reported as a type error by type checkers + type_ = cast("type[object]", type_) + if is_type_alias_type(type_): + original_type = type_ # type: ignore[unreachable] + type_ = type_.__value__ # type: ignore[unreachable] + + # unwrap `Annotated[T, ...]` -> `T` + if metadata is not None: + meta: tuple[Any, ...] = tuple(metadata) + elif is_annotated_type(type_): + meta = get_args(type_)[1:] + type_ = extract_type_arg(type_, 0) + else: + meta = tuple() + + # we need to use the origin class for any types that are subscripted generics + # e.g. Dict[str, object] + origin = get_origin(type_) or type_ + args = get_args(type_) + + if is_union(origin): + try: + return validate_type(type_=cast("type[object]", original_type or type_), value=value) + except Exception: + pass + + # if the type is a discriminated union then we want to construct the right variant + # in the union, even if the data doesn't match exactly, otherwise we'd break code + # that relies on the constructed class types, e.g. + # + # class FooType: + # kind: Literal['foo'] + # value: str + # + # class BarType: + # kind: Literal['bar'] + # value: int + # + # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then + # we'd end up constructing `FooType` when it should be `BarType`. + discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta) + if discriminator and is_mapping(value): + variant_value = value.get(discriminator.field_alias_from or discriminator.field_name) + if variant_value and isinstance(variant_value, str): + variant_type = discriminator.mapping.get(variant_value) + if variant_type: + return construct_type(type_=variant_type, value=value) + + # if the data is not valid, use the first variant that doesn't fail while deserializing + for variant in args: + try: + return construct_type(value=value, type_=variant) + except Exception: + continue + + raise RuntimeError(f"Could not convert data into a valid instance of {type_}") + + if origin == dict: + if not is_mapping(value): + return value + + _, items_type = get_args(type_) # Dict[_, items_type] + return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} + + if ( + not is_literal_type(type_) + and inspect.isclass(origin) + and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) + ): + if is_list(value): + return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] + + if is_mapping(value): + if issubclass(type_, BaseModel): + return type_.construct(**value) # type: ignore[arg-type] + + return cast(Any, type_).construct(**value) + + if origin == list: + if not is_list(value): + return value + + inner_type = args[0] # List[inner_type] + return [construct_type(value=entry, type_=inner_type) for entry in value] + + if origin == float: + if isinstance(value, int): + coerced = float(value) + if coerced != value: + return value + return coerced + + return value + + if type_ == datetime: + try: + return parse_datetime(value) # type: ignore + except Exception: + return value + + if type_ == date: + try: + return parse_date(value) # type: ignore + except Exception: + return value + + return value + + +@runtime_checkable +class CachedDiscriminatorType(Protocol): + __discriminator__: DiscriminatorDetails + + +class DiscriminatorDetails: + field_name: str + """The name of the discriminator field in the variant class, e.g. + + ```py + class Foo(BaseModel): + type: Literal['foo'] + ``` + + Will result in field_name='type' + """ + + field_alias_from: str | None + """The name of the discriminator field in the API response, e.g. + + ```py + class Foo(BaseModel): + type: Literal['foo'] = Field(alias='type_from_api') + ``` + + Will result in field_alias_from='type_from_api' + """ + + mapping: dict[str, type] + """Mapping of discriminator value to variant type, e.g. + + {'foo': FooVariant, 'bar': BarVariant} + """ + + def __init__( + self, + *, + mapping: dict[str, type], + discriminator_field: str, + discriminator_alias: str | None, + ) -> None: + self.mapping = mapping + self.field_name = discriminator_field + self.field_alias_from = discriminator_alias + + +def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: + if isinstance(union, CachedDiscriminatorType): + return union.__discriminator__ + + discriminator_field_name: str | None = None + + for annotation in meta_annotations: + if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None: + discriminator_field_name = annotation.discriminator + break + + if not discriminator_field_name: + return None + + mapping: dict[str, type] = {} + discriminator_alias: str | None = None + + for variant in get_args(union): + variant = strip_annotated_type(variant) + if is_basemodel_type(variant): + if PYDANTIC_V2: + field = _extract_field_schema_pv2(variant, discriminator_field_name) + if not field: + continue + + # Note: if one variant defines an alias then they all should + discriminator_alias = field.get("serialization_alias") + + field_schema = field["schema"] + + if field_schema["type"] == "literal": + for entry in cast("LiteralSchema", field_schema)["expected"]: + if isinstance(entry, str): + mapping[entry] = variant + else: + field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + if not field_info: + continue + + # Note: if one variant defines an alias then they all should + discriminator_alias = field_info.alias + + if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): + for entry in get_args(annotation): + if isinstance(entry, str): + mapping[entry] = variant + + if not mapping: + return None + + details = DiscriminatorDetails( + mapping=mapping, + discriminator_field=discriminator_field_name, + discriminator_alias=discriminator_alias, + ) + cast(CachedDiscriminatorType, union).__discriminator__ = details + return details + + +def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: + schema = model.__pydantic_core_schema__ + if schema["type"] == "definitions": + schema = schema["schema"] + + if schema["type"] != "model": + return None + + schema = cast("ModelSchema", schema) + fields_schema = schema["schema"] + if fields_schema["type"] != "model-fields": + return None + + fields_schema = cast("ModelFieldsSchema", fields_schema) + field = fields_schema["fields"].get(field_name) + if not field: + return None + + return cast("ModelField", field) # pyright: ignore[reportUnnecessaryCast] + + +def validate_type(*, type_: type[_T], value: object) -> _T: + """Strict validation that the given value matches the expected type""" + if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): + return cast(_T, parse_obj(type_, value)) + + return cast(_T, _validate_non_model_type(type_=type_, value=value)) + + +def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: + """Add a pydantic config for the given type. + + Note: this is a no-op on Pydantic v1. + """ + setattr(typ, "__pydantic_config__", config) # noqa: B010 + + +# our use of subclassing here causes weirdness for type checkers, +# so we just pretend that we don't subclass +if TYPE_CHECKING: + GenericModel = BaseModel +else: + + class GenericModel(BaseGenericModel, BaseModel): + pass + + +if PYDANTIC_V2: + from pydantic import TypeAdapter as _TypeAdapter + + _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) + + if TYPE_CHECKING: + from pydantic import TypeAdapter + else: + TypeAdapter = _CachedTypeAdapter + + def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: + return TypeAdapter(type_).validate_python(value) + +elif not TYPE_CHECKING: # TODO: condition is weird + + class RootModel(GenericModel, Generic[_T]): + """Used as a placeholder to easily convert runtime types to a Pydantic format + to provide validation. + + For example: + ```py + validated = RootModel[int](__root__="5").__root__ + # validated: 5 + ``` + """ + + __root__: _T + + def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: + model = _create_pydantic_model(type_).validate(value) + return cast(_T, model.__root__) + + def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]: + return RootModel[type_] # type: ignore + + +class FinalRequestOptionsInput(TypedDict, total=False): + method: Required[str] + url: Required[str] + params: Query + headers: Headers + max_retries: int + timeout: float | Timeout | None + files: HttpxRequestFiles | None + idempotency_key: str + json_data: Body + extra_json: AnyMapping + follow_redirects: bool + + +@final +class FinalRequestOptions(pydantic.BaseModel): + method: str + url: str + params: Query = {} + headers: Union[Headers, NotGiven] = NotGiven() + max_retries: Union[int, NotGiven] = NotGiven() + timeout: Union[float, Timeout, None, NotGiven] = NotGiven() + files: Union[HttpxRequestFiles, None] = None + idempotency_key: Union[str, None] = None + post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() + follow_redirects: Union[bool, 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 + extra_json: Union[AnyMapping, None] = None + + if PYDANTIC_V2: + model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) + else: + + class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] + arbitrary_types_allowed: bool = True + + def get_max_retries(self, max_retries: int) -> int: + if isinstance(self.max_retries, NotGiven): + return max_retries + return self.max_retries + + def _strip_raw_response_header(self) -> None: + if not is_given(self.headers): + return + + if self.headers.get(RAW_RESPONSE_HEADER): + self.headers = {**self.headers} + self.headers.pop(RAW_RESPONSE_HEADER) + + # override the `construct` method so that we can run custom transformations. + # this is necessary as we don't want to do any actual runtime type checking + # (which means we can't use validators) but we do want to ensure that `NotGiven` + # values are not present + # + # type ignore required because we're adding explicit types to `**values` + @classmethod + def construct( # type: ignore + cls, + _fields_set: set[str] | None = None, + **values: Unpack[FinalRequestOptionsInput], + ) -> FinalRequestOptions: + kwargs: dict[str, Any] = { + # we unconditionally call `strip_not_given` on any value + # as it will just ignore any non-mapping types + key: strip_not_given(value) + for key, value in values.items() + } + if PYDANTIC_V2: + return super().model_construct(_fields_set, **kwargs) + return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + + if not TYPE_CHECKING: + # type checkers incorrectly complain about this assignment + model_construct = construct diff --git a/src/gitpod/_qs.py b/src/gitpod/_qs.py new file mode 100644 index 0000000..274320c --- /dev/null +++ b/src/gitpod/_qs.py @@ -0,0 +1,150 @@ +from __future__ import annotations + +from typing import Any, List, Tuple, Union, Mapping, TypeVar +from urllib.parse import parse_qs, urlencode +from typing_extensions import Literal, get_args + +from ._types import NOT_GIVEN, NotGiven, NotGivenOr +from ._utils import flatten + +_T = TypeVar("_T") + + +ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] +NestedFormat = Literal["dots", "brackets"] + +PrimitiveData = Union[str, int, float, bool, None] +# this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] +# https://github.com/microsoft/pyright/issues/3555 +Data = Union[PrimitiveData, List[Any], Tuple[Any], "Mapping[str, Any]"] +Params = Mapping[str, Data] + + +class Querystring: + array_format: ArrayFormat + nested_format: NestedFormat + + def __init__( + self, + *, + array_format: ArrayFormat = "repeat", + nested_format: NestedFormat = "brackets", + ) -> None: + self.array_format = array_format + self.nested_format = nested_format + + def parse(self, query: str) -> Mapping[str, object]: + # Note: custom format syntax is not supported yet + return parse_qs(query) + + def stringify( + self, + params: Params, + *, + array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, + nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + ) -> str: + return urlencode( + self.stringify_items( + params, + array_format=array_format, + nested_format=nested_format, + ) + ) + + def stringify_items( + self, + params: Params, + *, + array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, + nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + ) -> list[tuple[str, str]]: + opts = Options( + qs=self, + array_format=array_format, + nested_format=nested_format, + ) + return flatten([self._stringify_item(key, value, opts) for key, value in params.items()]) + + def _stringify_item( + self, + key: str, + value: Data, + opts: Options, + ) -> list[tuple[str, str]]: + if isinstance(value, Mapping): + items: list[tuple[str, str]] = [] + nested_format = opts.nested_format + for subkey, subvalue in value.items(): + items.extend( + self._stringify_item( + # TODO: error if unknown format + f"{key}.{subkey}" if nested_format == "dots" else f"{key}[{subkey}]", + subvalue, + opts, + ) + ) + return items + + if isinstance(value, (list, tuple)): + array_format = opts.array_format + if array_format == "comma": + return [ + ( + key, + ",".join(self._primitive_value_to_str(item) for item in value if item is not None), + ), + ] + elif array_format == "repeat": + items = [] + for item in value: + items.extend(self._stringify_item(key, item, opts)) + return items + elif array_format == "indices": + raise NotImplementedError("The array indices format is not supported yet") + elif array_format == "brackets": + items = [] + key = key + "[]" + for item in value: + items.extend(self._stringify_item(key, item, opts)) + return items + else: + raise NotImplementedError( + f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" + ) + + serialised = self._primitive_value_to_str(value) + if not serialised: + return [] + return [(key, serialised)] + + def _primitive_value_to_str(self, value: PrimitiveData) -> str: + # copied from httpx + if value is True: + return "true" + elif value is False: + return "false" + elif value is None: + return "" + return str(value) + + +_qs = Querystring() +parse = _qs.parse +stringify = _qs.stringify +stringify_items = _qs.stringify_items + + +class Options: + array_format: ArrayFormat + nested_format: NestedFormat + + def __init__( + self, + qs: Querystring = _qs, + *, + array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, + nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + ) -> None: + self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format + self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/src/gitpod/_resource.py b/src/gitpod/_resource.py new file mode 100644 index 0000000..7447644 --- /dev/null +++ b/src/gitpod/_resource.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import time +from typing import TYPE_CHECKING + +import anyio + +if TYPE_CHECKING: + from ._client import Gitpod, AsyncGitpod + + +class SyncAPIResource: + _client: Gitpod + + def __init__(self, client: Gitpod) -> None: + self._client = client + self._get = client.get + self._post = client.post + self._patch = client.patch + self._put = client.put + self._delete = client.delete + self._get_api_list = client.get_api_list + + def _sleep(self, seconds: float) -> None: + time.sleep(seconds) + + +class AsyncAPIResource: + _client: AsyncGitpod + + def __init__(self, client: AsyncGitpod) -> None: + self._client = client + self._get = client.get + self._post = client.post + self._patch = client.patch + self._put = client.put + self._delete = client.delete + self._get_api_list = client.get_api_list + + async def _sleep(self, seconds: float) -> None: + await anyio.sleep(seconds) diff --git a/src/gitpod/_response.py b/src/gitpod/_response.py new file mode 100644 index 0000000..6211d72 --- /dev/null +++ b/src/gitpod/_response.py @@ -0,0 +1,852 @@ +from __future__ import annotations + +import os +import inspect +import logging +import datetime +import functools +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Union, + Generic, + TypeVar, + Callable, + Iterator, + AsyncIterator, + cast, + overload, +) +from typing_extensions import Awaitable, ParamSpec, override, get_origin + +import anyio +import httpx +import pydantic + +from ._types import NoneType +from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base +from ._models import BaseModel, is_basemodel +from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER +from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type +from ._exceptions import GitpodError, APIResponseValidationError +from ._decoders.jsonl import JSONLDecoder, AsyncJSONLDecoder + +if TYPE_CHECKING: + from ._models import FinalRequestOptions + from ._base_client import BaseClient + + +P = ParamSpec("P") +R = TypeVar("R") +_T = TypeVar("_T") +_APIResponseT = TypeVar("_APIResponseT", bound="APIResponse[Any]") +_AsyncAPIResponseT = TypeVar("_AsyncAPIResponseT", bound="AsyncAPIResponse[Any]") + +log: logging.Logger = logging.getLogger(__name__) + + +class BaseAPIResponse(Generic[R]): + _cast_to: type[R] + _client: BaseClient[Any, Any] + _parsed_by_type: dict[type[Any], Any] + _is_sse_stream: bool + _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None + _options: FinalRequestOptions + + http_response: httpx.Response + + retries_taken: int + """The number of retries made. If no retries happened this will be `0`""" + + def __init__( + self, + *, + raw: httpx.Response, + cast_to: type[R], + client: BaseClient[Any, Any], + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + options: FinalRequestOptions, + retries_taken: int = 0, + ) -> None: + self._cast_to = cast_to + self._client = client + self._parsed_by_type = {} + self._is_sse_stream = stream + self._stream_cls = stream_cls + self._options = options + self.http_response = raw + self.retries_taken = retries_taken + + @property + def headers(self) -> httpx.Headers: + return self.http_response.headers + + @property + def http_request(self) -> httpx.Request: + """Returns the httpx Request instance associated with the current response.""" + return self.http_response.request + + @property + def status_code(self) -> int: + return self.http_response.status_code + + @property + def url(self) -> httpx.URL: + """Returns the URL for which the request was made.""" + return self.http_response.url + + @property + def method(self) -> str: + return self.http_request.method + + @property + def http_version(self) -> str: + return self.http_response.http_version + + @property + def elapsed(self) -> datetime.timedelta: + """The time taken for the complete request/response cycle to complete.""" + return self.http_response.elapsed + + @property + def is_closed(self) -> bool: + """Whether or not the response body has been closed. + + If this is False then there is response data that has not been read yet. + You must either fully consume the response body or call `.close()` + before discarding the response to prevent resource leaks. + """ + return self.http_response.is_closed + + @override + def __repr__(self) -> str: + return ( + f"<{self.__class__.__name__} [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>" + ) + + def _parse(self, *, to: type[_T] | None = None) -> R | _T: + cast_to = to if to is not None else self._cast_to + + # unwrap `TypeAlias('Name', T)` -> `T` + if is_type_alias_type(cast_to): + cast_to = cast_to.__value__ # type: ignore[unreachable] + + # unwrap `Annotated[T, ...]` -> `T` + if cast_to and is_annotated_type(cast_to): + cast_to = extract_type_arg(cast_to, 0) + + origin = get_origin(cast_to) or cast_to + + if inspect.isclass(origin): + if issubclass(cast(Any, origin), JSONLDecoder): + return cast( + R, + cast("type[JSONLDecoder[Any]]", cast_to)( + raw_iterator=self.http_response.iter_bytes(chunk_size=64), + line_type=extract_type_arg(cast_to, 0), + http_response=self.http_response, + ), + ) + + if issubclass(cast(Any, origin), AsyncJSONLDecoder): + return cast( + R, + cast("type[AsyncJSONLDecoder[Any]]", cast_to)( + raw_iterator=self.http_response.aiter_bytes(chunk_size=64), + line_type=extract_type_arg(cast_to, 0), + http_response=self.http_response, + ), + ) + + if self._is_sse_stream: + if to: + if not is_stream_class_type(to): + raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}") + + return cast( + _T, + to( + cast_to=extract_stream_chunk_type( + to, + failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]", + ), + response=self.http_response, + client=cast(Any, self._client), + ), + ) + + if self._stream_cls: + return cast( + R, + self._stream_cls( + cast_to=extract_stream_chunk_type(self._stream_cls), + response=self.http_response, + client=cast(Any, self._client), + ), + ) + + stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls) + if stream_cls is None: + raise MissingStreamClassError() + + return cast( + R, + stream_cls( + cast_to=cast_to, + response=self.http_response, + client=cast(Any, self._client), + ), + ) + + if cast_to is NoneType: + return cast(R, None) + + response = self.http_response + if cast_to == str: + return cast(R, response.text) + + if cast_to == bytes: + return cast(R, response.content) + + if cast_to == int: + return cast(R, int(response.text)) + + if cast_to == float: + return cast(R, float(response.text)) + + if cast_to == bool: + return cast(R, response.text.lower() == "true") + + if origin == APIResponse: + raise RuntimeError("Unexpected state - cast_to is `APIResponse`") + + if inspect.isclass(origin) and issubclass(origin, httpx.Response): + # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response + # and pass that class to our request functions. We cannot change the variance to be either + # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct + # the response class ourselves but that is something that should be supported directly in httpx + # as it would be easy to incorrectly construct the Response object due to the multitude of arguments. + if cast_to != httpx.Response: + raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") + return cast(R, response) + + if ( + inspect.isclass( + origin # pyright: ignore[reportUnknownArgumentType] + ) + and not issubclass(origin, BaseModel) + and issubclass(origin, pydantic.BaseModel) + ): + raise TypeError("Pydantic models must subclass our base model type, e.g. `from gitpod import BaseModel`") + + if ( + cast_to is not object + and not origin is list + and not origin is dict + and not origin is Union + and not issubclass(origin, BaseModel) + ): + raise RuntimeError( + f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}." + ) + + # split is required to handle cases where additional information is included + # in the response, e.g. application/json; charset=utf-8 + content_type, *_ = response.headers.get("content-type", "*").split(";") + if not content_type.endswith("json"): + if is_basemodel(cast_to): + try: + data = response.json() + except Exception as exc: + log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc) + else: + return self._client._process_response_data( + data=data, + cast_to=cast_to, # type: ignore + response=response, + ) + + if self._client._strict_response_validation: + raise APIResponseValidationError( + response=response, + message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.", + body=response.text, + ) + + # If the API responds with content that isn't JSON then we just return + # the (decoded) text without performing any parsing so that you can still + # handle the response however you need to. + return response.text # type: ignore + + data = response.json() + + return self._client._process_response_data( + data=data, + cast_to=cast_to, # type: ignore + response=response, + ) + + +class APIResponse(BaseAPIResponse[R]): + @overload + def parse(self, *, to: type[_T]) -> _T: ... + + @overload + def parse(self) -> R: ... + + def parse(self, *, to: type[_T] | None = None) -> R | _T: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + + You can customise the type that the response is parsed into through + the `to` argument, e.g. + + ```py + from gitpod import BaseModel + + + class MyModel(BaseModel): + foo: str + + + obj = response.parse(to=MyModel) + print(obj.foo) + ``` + + We support parsing: + - `BaseModel` + - `dict` + - `list` + - `Union` + - `str` + - `int` + - `float` + - `httpx.Response` + """ + cache_key = to if to is not None else self._cast_to + cached = self._parsed_by_type.get(cache_key) + if cached is not None: + return cached # type: ignore[no-any-return] + + if not self._is_sse_stream: + self.read() + + parsed = self._parse(to=to) + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed_by_type[cache_key] = parsed + return parsed + + def read(self) -> bytes: + """Read and return the binary response content.""" + try: + return self.http_response.read() + except httpx.StreamConsumed as exc: + # The default error raised by httpx isn't very + # helpful in our case so we re-raise it with + # a different error message. + raise StreamAlreadyConsumed() from exc + + def text(self) -> str: + """Read and decode the response content into a string.""" + self.read() + return self.http_response.text + + def json(self) -> object: + """Read and decode the JSON response content.""" + self.read() + return self.http_response.json() + + def close(self) -> None: + """Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + self.http_response.close() + + def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: + """ + A byte-iterator over the decoded response content. + + This automatically handles gzip, deflate and brotli encoded responses. + """ + for chunk in self.http_response.iter_bytes(chunk_size): + yield chunk + + def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: + """A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + for chunk in self.http_response.iter_text(chunk_size): + yield chunk + + def iter_lines(self) -> Iterator[str]: + """Like `iter_text()` but will only yield chunks for each line""" + for chunk in self.http_response.iter_lines(): + yield chunk + + +class AsyncAPIResponse(BaseAPIResponse[R]): + @overload + async def parse(self, *, to: type[_T]) -> _T: ... + + @overload + async def parse(self) -> R: ... + + async def parse(self, *, to: type[_T] | None = None) -> R | _T: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + + You can customise the type that the response is parsed into through + the `to` argument, e.g. + + ```py + from gitpod import BaseModel + + + class MyModel(BaseModel): + foo: str + + + obj = response.parse(to=MyModel) + print(obj.foo) + ``` + + We support parsing: + - `BaseModel` + - `dict` + - `list` + - `Union` + - `str` + - `httpx.Response` + """ + cache_key = to if to is not None else self._cast_to + cached = self._parsed_by_type.get(cache_key) + if cached is not None: + return cached # type: ignore[no-any-return] + + if not self._is_sse_stream: + await self.read() + + parsed = self._parse(to=to) + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed_by_type[cache_key] = parsed + return parsed + + async def read(self) -> bytes: + """Read and return the binary response content.""" + try: + return await self.http_response.aread() + except httpx.StreamConsumed as exc: + # the default error raised by httpx isn't very + # helpful in our case so we re-raise it with + # a different error message + raise StreamAlreadyConsumed() from exc + + async def text(self) -> str: + """Read and decode the response content into a string.""" + await self.read() + return self.http_response.text + + async def json(self) -> object: + """Read and decode the JSON response content.""" + await self.read() + return self.http_response.json() + + async def close(self) -> None: + """Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + await self.http_response.aclose() + + async def iter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: + """ + A byte-iterator over the decoded response content. + + This automatically handles gzip, deflate and brotli encoded responses. + """ + async for chunk in self.http_response.aiter_bytes(chunk_size): + yield chunk + + async def iter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: + """A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + async for chunk in self.http_response.aiter_text(chunk_size): + yield chunk + + async def iter_lines(self) -> AsyncIterator[str]: + """Like `iter_text()` but will only yield chunks for each line""" + async for chunk in self.http_response.aiter_lines(): + yield chunk + + +class BinaryAPIResponse(APIResponse[bytes]): + """Subclass of APIResponse providing helpers for dealing with binary data. + + Note: If you want to stream the response data instead of eagerly reading it + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + + def write_to_file( + self, + file: str | os.PathLike[str], + ) -> None: + """Write the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + + Note: if you want to stream the data to the file instead of writing + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + with open(file, mode="wb") as f: + for data in self.iter_bytes(): + f.write(data) + + +class AsyncBinaryAPIResponse(AsyncAPIResponse[bytes]): + """Subclass of APIResponse providing helpers for dealing with binary data. + + Note: If you want to stream the response data instead of eagerly reading it + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + + async def write_to_file( + self, + file: str | os.PathLike[str], + ) -> None: + """Write the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + + Note: if you want to stream the data to the file instead of writing + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.iter_bytes(): + await f.write(data) + + +class StreamedBinaryAPIResponse(APIResponse[bytes]): + def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + """Streams the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + """ + with open(file, mode="wb") as f: + for data in self.iter_bytes(chunk_size): + f.write(data) + + +class AsyncStreamedBinaryAPIResponse(AsyncAPIResponse[bytes]): + async def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + """Streams the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + """ + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.iter_bytes(chunk_size): + await f.write(data) + + +class MissingStreamClassError(TypeError): + def __init__(self) -> None: + super().__init__( + "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `gitpod._streaming` for reference", + ) + + +class StreamAlreadyConsumed(GitpodError): + """ + Attempted to read or stream content, but the content has already + been streamed. + + This can happen if you use a method like `.iter_lines()` and then attempt + to read th entire response body afterwards, e.g. + + ```py + response = await client.post(...) + async for line in response.iter_lines(): + ... # do something with `line` + + content = await response.read() + # ^ error + ``` + + If you want this behaviour you'll need to either manually accumulate the response + content or call `await response.read()` before iterating over the stream. + """ + + def __init__(self) -> None: + message = ( + "Attempted to read or stream some content, but the content has " + "already been streamed. " + "This could be due to attempting to stream the response " + "content more than once." + "\n\n" + "You can fix this by manually accumulating the response content while streaming " + "or by calling `.read()` before starting to stream." + ) + super().__init__(message) + + +class ResponseContextManager(Generic[_APIResponseT]): + """Context manager for ensuring that a request is not made + until it is entered and that the response will always be closed + when the context manager exits + """ + + def __init__(self, request_func: Callable[[], _APIResponseT]) -> None: + self._request_func = request_func + self.__response: _APIResponseT | None = None + + def __enter__(self) -> _APIResponseT: + self.__response = self._request_func() + return self.__response + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__response is not None: + self.__response.close() + + +class AsyncResponseContextManager(Generic[_AsyncAPIResponseT]): + """Context manager for ensuring that a request is not made + until it is entered and that the response will always be closed + when the context manager exits + """ + + def __init__(self, api_request: Awaitable[_AsyncAPIResponseT]) -> None: + self._api_request = api_request + self.__response: _AsyncAPIResponseT | None = None + + async def __aenter__(self) -> _AsyncAPIResponseT: + self.__response = await self._api_request + return self.__response + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__response is not None: + await self.__response.close() + + +def to_streamed_response_wrapper(func: Callable[P, R]) -> Callable[P, ResponseContextManager[APIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support streaming and returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResponse[R]]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + + kwargs["extra_headers"] = extra_headers + + make_request = functools.partial(func, *args, **kwargs) + + return ResponseContextManager(cast(Callable[[], APIResponse[R]], make_request)) + + return wrapped + + +def async_to_streamed_response_wrapper( + func: Callable[P, Awaitable[R]], +) -> Callable[P, AsyncResponseContextManager[AsyncAPIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support streaming and returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[AsyncAPIResponse[R]]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + + kwargs["extra_headers"] = extra_headers + + make_request = func(*args, **kwargs) + + return AsyncResponseContextManager(cast(Awaitable[AsyncAPIResponse[R]], make_request)) + + return wrapped + + +def to_custom_streamed_response_wrapper( + func: Callable[P, object], + response_cls: type[_APIResponseT], +) -> Callable[P, ResponseContextManager[_APIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support streaming and returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + make_request = functools.partial(func, *args, **kwargs) + + return ResponseContextManager(cast(Callable[[], _APIResponseT], make_request)) + + return wrapped + + +def async_to_custom_streamed_response_wrapper( + func: Callable[P, Awaitable[object]], + response_cls: type[_AsyncAPIResponseT], +) -> Callable[P, AsyncResponseContextManager[_AsyncAPIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support streaming and returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_AsyncAPIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + make_request = func(*args, **kwargs) + + return AsyncResponseContextManager(cast(Awaitable[_AsyncAPIResponseT], make_request)) + + return wrapped + + +def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]]: + """Higher order function that takes one of our bound API methods and wraps it + to support returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + + kwargs["extra_headers"] = extra_headers + + return cast(APIResponse[R], func(*args, **kwargs)) + + return wrapped + + +def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[AsyncAPIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + + kwargs["extra_headers"] = extra_headers + + return cast(AsyncAPIResponse[R], await func(*args, **kwargs)) + + return wrapped + + +def to_custom_raw_response_wrapper( + func: Callable[P, object], + response_cls: type[_APIResponseT], +) -> Callable[P, _APIResponseT]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + return cast(_APIResponseT, func(*args, **kwargs)) + + return wrapped + + +def async_to_custom_raw_response_wrapper( + func: Callable[P, Awaitable[object]], + response_cls: type[_AsyncAPIResponseT], +) -> Callable[P, Awaitable[_AsyncAPIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs)) + + return wrapped + + +def extract_response_type(typ: type[BaseAPIResponse[Any]]) -> type: + """Given a type like `APIResponse[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyResponse(APIResponse[bytes]): + ... + + extract_response_type(MyResponse) -> bytes + ``` + """ + return extract_type_var_from_base( + typ, + generic_bases=cast("tuple[type, ...]", (BaseAPIResponse, APIResponse, AsyncAPIResponse)), + index=0, + ) diff --git a/src/gitpod/_streaming.py b/src/gitpod/_streaming.py new file mode 100644 index 0000000..deacb4d --- /dev/null +++ b/src/gitpod/_streaming.py @@ -0,0 +1,333 @@ +# Note: initially copied from https://github.com/florimondmanca/httpx-sse/blob/master/src/httpx_sse/_decoders.py +from __future__ import annotations + +import json +import inspect +from types import TracebackType +from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast +from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable + +import httpx + +from ._utils import extract_type_var_from_base + +if TYPE_CHECKING: + from ._client import Gitpod, AsyncGitpod + + +_T = TypeVar("_T") + + +class Stream(Generic[_T]): + """Provides the core interface to iterate over a synchronous stream response.""" + + response: httpx.Response + + _decoder: SSEBytesDecoder + + def __init__( + self, + *, + cast_to: type[_T], + response: httpx.Response, + client: Gitpod, + ) -> None: + self.response = response + self._cast_to = cast_to + self._client = client + self._decoder = client._make_sse_decoder() + self._iterator = self.__stream__() + + def __next__(self) -> _T: + return self._iterator.__next__() + + def __iter__(self) -> Iterator[_T]: + for item in self._iterator: + yield item + + def _iter_events(self) -> Iterator[ServerSentEvent]: + yield from self._decoder.iter_bytes(self.response.iter_bytes()) + + def __stream__(self) -> Iterator[_T]: + cast_to = cast(Any, self._cast_to) + response = self.response + process_data = self._client._process_response_data + iterator = self._iter_events() + + for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + + # Ensure the entire stream is consumed + for _sse in iterator: + ... + + def __enter__(self) -> Self: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def close(self) -> None: + """ + Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + self.response.close() + + +class AsyncStream(Generic[_T]): + """Provides the core interface to iterate over an asynchronous stream response.""" + + response: httpx.Response + + _decoder: SSEDecoder | SSEBytesDecoder + + def __init__( + self, + *, + cast_to: type[_T], + response: httpx.Response, + client: AsyncGitpod, + ) -> None: + self.response = response + self._cast_to = cast_to + self._client = client + self._decoder = client._make_sse_decoder() + self._iterator = self.__stream__() + + async def __anext__(self) -> _T: + return await self._iterator.__anext__() + + async def __aiter__(self) -> AsyncIterator[_T]: + async for item in self._iterator: + yield item + + async def _iter_events(self) -> AsyncIterator[ServerSentEvent]: + async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()): + yield sse + + async def __stream__(self) -> AsyncIterator[_T]: + cast_to = cast(Any, self._cast_to) + response = self.response + process_data = self._client._process_response_data + iterator = self._iter_events() + + async for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + + # Ensure the entire stream is consumed + async for _sse in iterator: + ... + + async def __aenter__(self) -> Self: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.close() + + async def close(self) -> None: + """ + Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + await self.response.aclose() + + +class ServerSentEvent: + def __init__( + self, + *, + event: str | None = None, + data: str | None = None, + id: str | None = None, + retry: int | None = None, + ) -> None: + if data is None: + data = "" + + self._id = id + self._data = data + self._event = event or None + self._retry = retry + + @property + def event(self) -> str | None: + return self._event + + @property + def id(self) -> str | None: + return self._id + + @property + def retry(self) -> int | None: + return self._retry + + @property + def data(self) -> str: + return self._data + + def json(self) -> Any: + return json.loads(self.data) + + @override + def __repr__(self) -> str: + return f"ServerSentEvent(event={self.event}, data={self.data}, id={self.id}, retry={self.retry})" + + +class SSEDecoder: + _data: list[str] + _event: str | None + _retry: int | None + _last_event_id: str | None + + def __init__(self) -> None: + self._event = None + self._data = [] + self._last_event_id = None + self._retry = None + + def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + for chunk in self._iter_chunks(iterator): + # Split before decoding so splitlines() only uses \r and \n + for raw_line in chunk.splitlines(): + line = raw_line.decode("utf-8") + sse = self.decode(line) + if sse: + yield sse + + def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]: + """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" + data = b"" + for chunk in iterator: + for line in chunk.splitlines(keepends=True): + data += line + if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): + yield data + data = b"" + if data: + yield data + + async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + async for chunk in self._aiter_chunks(iterator): + # Split before decoding so splitlines() only uses \r and \n + for raw_line in chunk.splitlines(): + line = raw_line.decode("utf-8") + sse = self.decode(line) + if sse: + yield sse + + async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]: + """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" + data = b"" + async for chunk in iterator: + for line in chunk.splitlines(keepends=True): + data += line + if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): + yield data + data = b"" + if data: + yield data + + def decode(self, line: str) -> ServerSentEvent | None: + # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 + + if not line: + if not self._event and not self._data and not self._last_event_id and self._retry is None: + return None + + sse = ServerSentEvent( + event=self._event, + data="\n".join(self._data), + id=self._last_event_id, + retry=self._retry, + ) + + # NOTE: as per the SSE spec, do not reset last_event_id. + self._event = None + self._data = [] + self._retry = None + + return sse + + if line.startswith(":"): + return None + + fieldname, _, value = line.partition(":") + + if value.startswith(" "): + value = value[1:] + + if fieldname == "event": + self._event = value + elif fieldname == "data": + self._data.append(value) + elif fieldname == "id": + if "\0" in value: + pass + else: + self._last_event_id = value + elif fieldname == "retry": + try: + self._retry = int(value) + except (TypeError, ValueError): + pass + else: + pass # Field is ignored. + + return None + + +@runtime_checkable +class SSEBytesDecoder(Protocol): + def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + ... + + def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: + """Given an async iterator that yields raw binary data, iterate over it & yield every event encountered""" + ... + + +def is_stream_class_type(typ: type) -> TypeGuard[type[Stream[object]] | type[AsyncStream[object]]]: + """TypeGuard for determining whether or not the given type is a subclass of `Stream` / `AsyncStream`""" + origin = get_origin(typ) or typ + return inspect.isclass(origin) and issubclass(origin, (Stream, AsyncStream)) + + +def extract_stream_chunk_type( + stream_cls: type, + *, + failure_message: str | None = None, +) -> type: + """Given a type like `Stream[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyStream(Stream[bytes]): + ... + + extract_stream_chunk_type(MyStream) -> bytes + ``` + """ + from ._base_client import Stream, AsyncStream + + return extract_type_var_from_base( + stream_cls, + index=0, + generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)), + failure_message=failure_message, + ) diff --git a/src/gitpod/_types.py b/src/gitpod/_types.py new file mode 100644 index 0000000..b5cea32 --- /dev/null +++ b/src/gitpod/_types.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +from os import PathLike +from typing import ( + IO, + TYPE_CHECKING, + Any, + Dict, + List, + Type, + Tuple, + Union, + Mapping, + TypeVar, + Callable, + Optional, + Sequence, +) +from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable + +import httpx +import pydantic +from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport + +if TYPE_CHECKING: + from ._models import BaseModel + from ._response import APIResponse, AsyncAPIResponse + +Transport = BaseTransport +AsyncTransport = AsyncBaseTransport +Query = Mapping[str, object] +Body = object +AnyMapping = Mapping[str, object] +ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) +_T = TypeVar("_T") + + +# Approximates httpx internal ProxiesTypes and RequestFiles types +# while adding support for `PathLike` instances +ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]] +ProxiesTypes = Union[str, Proxy, ProxiesDict] +if TYPE_CHECKING: + Base64FileInput = Union[IO[bytes], PathLike[str]] + FileContent = Union[IO[bytes], bytes, PathLike[str]] +else: + Base64FileInput = Union[IO[bytes], PathLike] + FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. +FileTypes = Union[ + # file (or bytes) + FileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], FileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], FileContent, Optional[str]], + # (filename, file (or bytes), content_type, headers) + Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], +] +RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] + +# duplicate of the above but without our custom file support +HttpxFileContent = Union[IO[bytes], bytes] +HttpxFileTypes = Union[ + # file (or bytes) + HttpxFileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], HttpxFileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], HttpxFileContent, Optional[str]], + # (filename, file (or bytes), content_type, headers) + Tuple[Optional[str], HttpxFileContent, Optional[str], Mapping[str, str]], +] +HttpxRequestFiles = Union[Mapping[str, HttpxFileTypes], Sequence[Tuple[str, HttpxFileTypes]]] + +# Workaround to support (cast_to: Type[ResponseT]) -> ResponseT +# where ResponseT includes `None`. In order to support directly +# passing `None`, overloads would have to be defined for every +# method that uses `ResponseT` which would lead to an unacceptable +# amount of code duplication and make it unreadable. See _base_client.py +# for example usage. +# +# This unfortunately means that you will either have +# to import this type and pass it explicitly: +# +# from gitpod import NoneType +# client.get('/foo', cast_to=NoneType) +# +# or build it yourself: +# +# client.get('/foo', cast_to=type(None)) +if TYPE_CHECKING: + NoneType: Type[None] +else: + NoneType = type(None) + + +class RequestOptions(TypedDict, total=False): + headers: Headers + max_retries: int + timeout: float | Timeout | None + params: Query + extra_json: AnyMapping + idempotency_key: str + follow_redirects: bool + + +# Sentinel class used until PEP 0661 is accepted +class NotGiven: + """ + A sentinel singleton class used to distinguish omitted keyword arguments + from those passed in with the value None (which may have different behavior). + + For example: + + ```py + def get(timeout: Union[int, NotGiven, None] = NotGiven()) -> Response: ... + + + get(timeout=1) # 1s timeout + get(timeout=None) # No timeout + get() # Default timeout behavior, which may not be statically known at the method definition. + ``` + """ + + def __bool__(self) -> Literal[False]: + return False + + @override + def __repr__(self) -> str: + return "NOT_GIVEN" + + +NotGivenOr = Union[_T, NotGiven] +NOT_GIVEN = NotGiven() + + +class Omit: + """In certain situations you need to be able to represent a case where a default value has + to be explicitly removed and `None` is not an appropriate substitute, for example: + + ```py + # as the default `Content-Type` header is `application/json` that will be sent + client.post("/upload/files", files={"file": b"my raw file content"}) + + # you can't explicitly override the header as it has to be dynamically generated + # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' + client.post(..., headers={"Content-Type": "multipart/form-data"}) + + # instead you can remove the default `application/json` header by passing Omit + client.post(..., headers={"Content-Type": Omit()}) + ``` + """ + + def __bool__(self) -> Literal[False]: + return False + + +@runtime_checkable +class ModelBuilderProtocol(Protocol): + @classmethod + def build( + cls: type[_T], + *, + response: Response, + data: object, + ) -> _T: ... + + +Headers = Mapping[str, Union[str, Omit]] + + +class HeadersLikeProtocol(Protocol): + def get(self, __key: str) -> str | None: ... + + +HeadersLike = Union[Headers, HeadersLikeProtocol] + +ResponseT = TypeVar( + "ResponseT", + bound=Union[ + object, + str, + None, + "BaseModel", + List[Any], + Dict[str, Any], + Response, + ModelBuilderProtocol, + "APIResponse[Any]", + "AsyncAPIResponse[Any]", + ], +) + +StrBytesIntFloat = Union[str, bytes, int, float] + +# Note: copied from Pydantic +# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79 +IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]] + +PostParser = Callable[[Any], Any] + + +@runtime_checkable +class InheritsGeneric(Protocol): + """Represents a type that has inherited from `Generic` + + The `__orig_bases__` property can be used to determine the resolved + type variable for a given base class. + """ + + __orig_bases__: tuple[_GenericAlias] + + +class _GenericAlias(Protocol): + __origin__: type[object] + + +class HttpxSendArgs(TypedDict, total=False): + auth: httpx.Auth + follow_redirects: bool diff --git a/src/gitpod/_utils/__init__.py b/src/gitpod/_utils/__init__.py new file mode 100644 index 0000000..d4fda26 --- /dev/null +++ b/src/gitpod/_utils/__init__.py @@ -0,0 +1,57 @@ +from ._sync import asyncify as asyncify +from ._proxy import LazyProxy as LazyProxy +from ._utils import ( + flatten as flatten, + is_dict as is_dict, + is_list as is_list, + is_given as is_given, + is_tuple as is_tuple, + json_safe as json_safe, + lru_cache as lru_cache, + is_mapping as is_mapping, + is_tuple_t as is_tuple_t, + parse_date as parse_date, + is_iterable as is_iterable, + is_sequence as is_sequence, + coerce_float as coerce_float, + is_mapping_t as is_mapping_t, + removeprefix as removeprefix, + removesuffix as removesuffix, + extract_files as extract_files, + is_sequence_t as is_sequence_t, + required_args as required_args, + coerce_boolean as coerce_boolean, + coerce_integer as coerce_integer, + file_from_path as file_from_path, + parse_datetime as parse_datetime, + strip_not_given as strip_not_given, + deepcopy_minimal as deepcopy_minimal, + get_async_library as get_async_library, + maybe_coerce_float as maybe_coerce_float, + get_required_header as get_required_header, + maybe_coerce_boolean as maybe_coerce_boolean, + maybe_coerce_integer as maybe_coerce_integer, +) +from ._typing import ( + is_list_type as is_list_type, + is_union_type as is_union_type, + extract_type_arg as extract_type_arg, + is_iterable_type as is_iterable_type, + is_required_type as is_required_type, + is_annotated_type as is_annotated_type, + is_type_alias_type as is_type_alias_type, + strip_annotated_type as strip_annotated_type, + extract_type_var_from_base as extract_type_var_from_base, +) +from ._streams import consume_sync_iterator as consume_sync_iterator, consume_async_iterator as consume_async_iterator +from ._transform import ( + PropertyInfo as PropertyInfo, + transform as transform, + async_transform as async_transform, + maybe_transform as maybe_transform, + async_maybe_transform as async_maybe_transform, +) +from ._reflection import ( + function_has_argument as function_has_argument, + assert_signatures_in_sync as assert_signatures_in_sync, +) diff --git a/src/gitpod/_utils/_logs.py b/src/gitpod/_utils/_logs.py new file mode 100644 index 0000000..229b952 --- /dev/null +++ b/src/gitpod/_utils/_logs.py @@ -0,0 +1,25 @@ +import os +import logging + +logger: logging.Logger = logging.getLogger("gitpod") +httpx_logger: logging.Logger = logging.getLogger("httpx") + + +def _basic_config() -> None: + # e.g. [2023-10-05 14:12:26 - gitpod._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" + logging.basicConfig( + format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + +def setup_logging() -> None: + env = os.environ.get("GITPOD_LOG") + if env == "debug": + _basic_config() + logger.setLevel(logging.DEBUG) + httpx_logger.setLevel(logging.DEBUG) + elif env == "info": + _basic_config() + logger.setLevel(logging.INFO) + httpx_logger.setLevel(logging.INFO) diff --git a/src/gitpod/_utils/_proxy.py b/src/gitpod/_utils/_proxy.py new file mode 100644 index 0000000..0f239a3 --- /dev/null +++ b/src/gitpod/_utils/_proxy.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Generic, TypeVar, Iterable, cast +from typing_extensions import override + +T = TypeVar("T") + + +class LazyProxy(Generic[T], ABC): + """Implements data methods to pretend that an instance is another instance. + + This includes forwarding attribute access and other methods. + """ + + # Note: we have to special case proxies that themselves return proxies + # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz` + + def __getattr__(self, attr: str) -> object: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied # pyright: ignore + return getattr(proxied, attr) + + @override + def __repr__(self) -> str: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied.__class__.__name__ + return repr(self.__get_proxied__()) + + @override + def __str__(self) -> str: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied.__class__.__name__ + return str(proxied) + + @override + def __dir__(self) -> Iterable[str]: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return [] + return proxied.__dir__() + + @property # type: ignore + @override + def __class__(self) -> type: # pyright: ignore + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) + if issubclass(type(proxied), LazyProxy): + return type(proxied) + return proxied.__class__ + + def __get_proxied__(self) -> T: + return self.__load__() + + def __as_proxied__(self) -> T: + """Helper method that returns the current proxy, typed as the loaded object""" + return cast(T, self) + + @abstractmethod + def __load__(self) -> T: ... diff --git a/src/gitpod/_utils/_reflection.py b/src/gitpod/_utils/_reflection.py new file mode 100644 index 0000000..89aa712 --- /dev/null +++ b/src/gitpod/_utils/_reflection.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +import inspect +from typing import Any, Callable + + +def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: + """Returns whether or not the given function has a specific parameter""" + sig = inspect.signature(func) + return arg_name in sig.parameters + + +def assert_signatures_in_sync( + source_func: Callable[..., Any], + check_func: Callable[..., Any], + *, + exclude_params: set[str] = set(), +) -> None: + """Ensure that the signature of the second function matches the first.""" + + check_sig = inspect.signature(check_func) + source_sig = inspect.signature(source_func) + + errors: list[str] = [] + + for name, source_param in source_sig.parameters.items(): + if name in exclude_params: + continue + + custom_param = check_sig.parameters.get(name) + if not custom_param: + errors.append(f"the `{name}` param is missing") + continue + + if custom_param.annotation != source_param.annotation: + errors.append( + f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}" + ) + continue + + if errors: + raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors)) diff --git a/src/gitpod/_utils/_resources_proxy.py b/src/gitpod/_utils/_resources_proxy.py new file mode 100644 index 0000000..7ffe977 --- /dev/null +++ b/src/gitpod/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `gitpod.resources` module. + + This is used so that we can lazily import `gitpod.resources` only when + needed *and* so that users can just import `gitpod` and reference `gitpod.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("gitpod.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() diff --git a/src/gitpod/_utils/_streams.py b/src/gitpod/_utils/_streams.py new file mode 100644 index 0000000..f4a0208 --- /dev/null +++ b/src/gitpod/_utils/_streams.py @@ -0,0 +1,12 @@ +from typing import Any +from typing_extensions import Iterator, AsyncIterator + + +def consume_sync_iterator(iterator: Iterator[Any]) -> None: + for _ in iterator: + ... + + +async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None: + async for _ in iterator: + ... diff --git a/src/gitpod/_utils/_sync.py b/src/gitpod/_utils/_sync.py new file mode 100644 index 0000000..ad7ec71 --- /dev/null +++ b/src/gitpod/_utils/_sync.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import sys +import asyncio +import functools +import contextvars +from typing import Any, TypeVar, Callable, Awaitable +from typing_extensions import ParamSpec + +import anyio +import sniffio +import anyio.to_thread + +T_Retval = TypeVar("T_Retval") +T_ParamSpec = ParamSpec("T_ParamSpec") + + +if sys.version_info >= (3, 9): + _asyncio_to_thread = asyncio.to_thread +else: + # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread + # for Python 3.8 support + async def _asyncio_to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs + ) -> Any: + """Asynchronously run function *func* in a separate thread. + + Any *args and **kwargs supplied for this function are directly passed + to *func*. Also, the current :class:`contextvars.Context` is propagated, + allowing context variables from the main thread to be accessed in the + separate thread. + + Returns a coroutine that can be awaited to get the eventual result of *func*. + """ + loop = asyncio.events.get_running_loop() + ctx = contextvars.copy_context() + func_call = functools.partial(ctx.run, func, *args, **kwargs) + return await loop.run_in_executor(None, func_call) + + +async def to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs +) -> T_Retval: + if sniffio.current_async_library() == "asyncio": + return await _asyncio_to_thread(func, *args, **kwargs) + + return await anyio.to_thread.run_sync( + functools.partial(func, *args, **kwargs), + ) + + +# inspired by `asyncer`, https://github.com/tiangolo/asyncer +def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: + """ + Take a blocking function and create an async one that receives the same + positional and keyword arguments. For python version 3.9 and above, it uses + asyncio.to_thread to run the function in a separate thread. For python version + 3.8, it uses locally defined copy of the asyncio.to_thread function which was + introduced in python 3.9. + + Usage: + + ```python + def blocking_func(arg1, arg2, kwarg1=None): + # blocking code + return result + + + result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) + ``` + + ## Arguments + + `function`: a blocking regular callable (e.g. a function) + + ## Return + + An async function that takes the same positional and keyword arguments as the + original one, that when called runs the same original function in a thread worker + and returns the result. + """ + + async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: + return await to_thread(function, *args, **kwargs) + + return wrapper diff --git a/src/gitpod/_utils/_transform.py b/src/gitpod/_utils/_transform.py new file mode 100644 index 0000000..b0cc20a --- /dev/null +++ b/src/gitpod/_utils/_transform.py @@ -0,0 +1,447 @@ +from __future__ import annotations + +import io +import base64 +import pathlib +from typing import Any, Mapping, TypeVar, cast +from datetime import date, datetime +from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints + +import anyio +import pydantic + +from ._utils import ( + is_list, + is_given, + lru_cache, + is_mapping, + is_iterable, +) +from .._files import is_base64_file_input +from ._typing import ( + is_list_type, + is_union_type, + extract_type_arg, + is_iterable_type, + is_required_type, + is_annotated_type, + strip_annotated_type, +) +from .._compat import get_origin, model_dump, is_typeddict + +_T = TypeVar("_T") + + +# TODO: support for drilling globals() and locals() +# TODO: ensure works correctly with forward references in all cases + + +PropertyFormat = Literal["iso8601", "base64", "custom"] + + +class PropertyInfo: + """Metadata class to be used in Annotated types to provide information about a given type. + + For example: + + class MyParams(TypedDict): + account_holder_name: Annotated[str, PropertyInfo(alias='accountHolderName')] + + This means that {'account_holder_name': 'Robert'} will be transformed to {'accountHolderName': 'Robert'} before being sent to the API. + """ + + alias: str | None + format: PropertyFormat | None + format_template: str | None + discriminator: str | None + + def __init__( + self, + *, + alias: str | None = None, + format: PropertyFormat | None = None, + format_template: str | None = None, + discriminator: str | None = None, + ) -> None: + self.alias = alias + self.format = format + self.format_template = format_template + self.discriminator = discriminator + + @override + def __repr__(self) -> str: + return f"{self.__class__.__name__}(alias='{self.alias}', format={self.format}, format_template='{self.format_template}', discriminator='{self.discriminator}')" + + +def maybe_transform( + data: object, + expected_type: object, +) -> Any | None: + """Wrapper over `transform()` that allows `None` to be passed. + + See `transform()` for more details. + """ + if data is None: + return None + return transform(data, expected_type) + + +# Wrapper over _transform_recursive providing fake types +def transform( + data: _T, + expected_type: object, +) -> _T: + """Transform dictionaries based off of type information from the given type, for example: + + ```py + class Params(TypedDict, total=False): + card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] + + + transformed = transform({"card_id": "<my card ID>"}, Params) + # {'cardID': '<my card ID>'} + ``` + + Any keys / data that does not have type information given will be included as is. + + It should be noted that the transformations that this function does are not represented in the type system. + """ + transformed = _transform_recursive(data, annotation=cast(type, expected_type)) + return cast(_T, transformed) + + +@lru_cache(maxsize=8096) +def _get_annotated_type(type_: type) -> type | None: + """If the given type is an `Annotated` type then it is returned, if not `None` is returned. + + This also unwraps the type when applicable, e.g. `Required[Annotated[T, ...]]` + """ + if is_required_type(type_): + # Unwrap `Required[Annotated[T, ...]]` to `Annotated[T, ...]` + type_ = get_args(type_)[0] + + if is_annotated_type(type_): + return type_ + + return None + + +def _maybe_transform_key(key: str, type_: type) -> str: + """Transform the given `data` based on the annotations provided in `type_`. + + Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. + """ + annotated_type = _get_annotated_type(type_) + if annotated_type is None: + # no `Annotated` definition for this type, no transformation needed + return key + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.alias is not None: + return annotation.alias + + return key + + +def _no_transform_needed(annotation: type) -> bool: + return annotation == float or annotation == int + + +def _transform_recursive( + data: object, + *, + annotation: type, + inner_type: type | None = None, +) -> object: + """Transform the given data against the expected type. + + Args: + annotation: The direct type annotation given to the particular piece of data. + This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc + + inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type + is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in + the list can be transformed using the metadata from the container type. + + Defaults to the same value as the `annotation` argument. + """ + if inner_type is None: + inner_type = annotation + + stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type + if is_typeddict(stripped_type) and is_mapping(data): + return _transform_typeddict(data, stripped_type) + + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + + if ( + # List[T] + (is_list_type(stripped_type) and is_list(data)) + # Iterable[T] + or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + + inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + + return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] + + if is_union_type(stripped_type): + # For union types we run the transformation against all subtypes to ensure that everything is transformed. + # + # TODO: there may be edge cases where the same normalized field name will transform to two different names + # in different subtypes. + for subtype in get_args(stripped_type): + data = _transform_recursive(data, annotation=annotation, inner_type=subtype) + return data + + if isinstance(data, pydantic.BaseModel): + return model_dump(data, exclude_unset=True, mode="json") + + annotated_type = _get_annotated_type(annotation) + if annotated_type is None: + return data + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.format is not None: + return _format_data(data, annotation.format, annotation.format_template) + + return data + + +def _format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: + if isinstance(data, (date, datetime)): + if format_ == "iso8601": + return data.isoformat() + + if format_ == "custom" and format_template is not None: + return data.strftime(format_template) + + if format_ == "base64" and is_base64_file_input(data): + binary: str | bytes | None = None + + if isinstance(data, pathlib.Path): + binary = data.read_bytes() + elif isinstance(data, io.IOBase): + binary = data.read() + + if isinstance(binary, str): # type: ignore[unreachable] + binary = binary.encode() + + if not isinstance(binary, bytes): + raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") + + return base64.b64encode(binary).decode("ascii") + + return data + + +def _transform_typeddict( + data: Mapping[str, object], + expected_type: type, +) -> Mapping[str, object]: + result: dict[str, object] = {} + annotations = get_type_hints(expected_type, include_extras=True) + for key, value in data.items(): + if not is_given(value): + # we don't need to include `NotGiven` values here as they'll + # be stripped out before the request is sent anyway + continue + + type_ = annotations.get(key) + if type_ is None: + # we do not have a type annotation for this field, leave it as is + result[key] = value + else: + result[_maybe_transform_key(key, type_)] = _transform_recursive(value, annotation=type_) + return result + + +async def async_maybe_transform( + data: object, + expected_type: object, +) -> Any | None: + """Wrapper over `async_transform()` that allows `None` to be passed. + + See `async_transform()` for more details. + """ + if data is None: + return None + return await async_transform(data, expected_type) + + +async def async_transform( + data: _T, + expected_type: object, +) -> _T: + """Transform dictionaries based off of type information from the given type, for example: + + ```py + class Params(TypedDict, total=False): + card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] + + + transformed = transform({"card_id": "<my card ID>"}, Params) + # {'cardID': '<my card ID>'} + ``` + + Any keys / data that does not have type information given will be included as is. + + It should be noted that the transformations that this function does are not represented in the type system. + """ + transformed = await _async_transform_recursive(data, annotation=cast(type, expected_type)) + return cast(_T, transformed) + + +async def _async_transform_recursive( + data: object, + *, + annotation: type, + inner_type: type | None = None, +) -> object: + """Transform the given data against the expected type. + + Args: + annotation: The direct type annotation given to the particular piece of data. + This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc + + inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type + is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in + the list can be transformed using the metadata from the container type. + + Defaults to the same value as the `annotation` argument. + """ + if inner_type is None: + inner_type = annotation + + stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type + if is_typeddict(stripped_type) and is_mapping(data): + return await _async_transform_typeddict(data, stripped_type) + + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + + if ( + # List[T] + (is_list_type(stripped_type) and is_list(data)) + # Iterable[T] + or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + + inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + + return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] + + if is_union_type(stripped_type): + # For union types we run the transformation against all subtypes to ensure that everything is transformed. + # + # TODO: there may be edge cases where the same normalized field name will transform to two different names + # in different subtypes. + for subtype in get_args(stripped_type): + data = await _async_transform_recursive(data, annotation=annotation, inner_type=subtype) + return data + + if isinstance(data, pydantic.BaseModel): + return model_dump(data, exclude_unset=True, mode="json") + + annotated_type = _get_annotated_type(annotation) + if annotated_type is None: + return data + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.format is not None: + return await _async_format_data(data, annotation.format, annotation.format_template) + + return data + + +async def _async_format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: + if isinstance(data, (date, datetime)): + if format_ == "iso8601": + return data.isoformat() + + if format_ == "custom" and format_template is not None: + return data.strftime(format_template) + + if format_ == "base64" and is_base64_file_input(data): + binary: str | bytes | None = None + + if isinstance(data, pathlib.Path): + binary = await anyio.Path(data).read_bytes() + elif isinstance(data, io.IOBase): + binary = data.read() + + if isinstance(binary, str): # type: ignore[unreachable] + binary = binary.encode() + + if not isinstance(binary, bytes): + raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") + + return base64.b64encode(binary).decode("ascii") + + return data + + +async def _async_transform_typeddict( + data: Mapping[str, object], + expected_type: type, +) -> Mapping[str, object]: + result: dict[str, object] = {} + annotations = get_type_hints(expected_type, include_extras=True) + for key, value in data.items(): + if not is_given(value): + # we don't need to include `NotGiven` values here as they'll + # be stripped out before the request is sent anyway + continue + + type_ = annotations.get(key) + if type_ is None: + # we do not have a type annotation for this field, leave it as is + result[key] = value + else: + result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) + return result + + +@lru_cache(maxsize=8096) +def get_type_hints( + obj: Any, + globalns: dict[str, Any] | None = None, + localns: Mapping[str, Any] | None = None, + include_extras: bool = False, +) -> dict[str, Any]: + return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/src/gitpod/_utils/_typing.py b/src/gitpod/_utils/_typing.py new file mode 100644 index 0000000..1bac954 --- /dev/null +++ b/src/gitpod/_utils/_typing.py @@ -0,0 +1,151 @@ +from __future__ import annotations + +import sys +import typing +import typing_extensions +from typing import Any, TypeVar, Iterable, cast +from collections import abc as _c_abc +from typing_extensions import ( + TypeIs, + Required, + Annotated, + get_args, + get_origin, +) + +from ._utils import lru_cache +from .._types import InheritsGeneric +from .._compat import is_union as _is_union + + +def is_annotated_type(typ: type) -> bool: + return get_origin(typ) == Annotated + + +def is_list_type(typ: type) -> bool: + return (get_origin(typ) or typ) == list + + +def is_iterable_type(typ: type) -> bool: + """If the given type is `typing.Iterable[T]`""" + origin = get_origin(typ) or typ + return origin == Iterable or origin == _c_abc.Iterable + + +def is_union_type(typ: type) -> bool: + return _is_union(get_origin(typ)) + + +def is_required_type(typ: type) -> bool: + return get_origin(typ) == Required + + +def is_typevar(typ: type) -> bool: + # type ignore is required because type checkers + # think this expression will always return False + return type(typ) == TypeVar # type: ignore + + +_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) +if sys.version_info >= (3, 12): + _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) + + +def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: + """Return whether the provided argument is an instance of `TypeAliasType`. + + ```python + type Int = int + is_type_alias_type(Int) + # > True + Str = TypeAliasType("Str", str) + is_type_alias_type(Str) + # > True + ``` + """ + return isinstance(tp, _TYPE_ALIAS_TYPES) + + +# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] +@lru_cache(maxsize=8096) +def strip_annotated_type(typ: type) -> type: + if is_required_type(typ) or is_annotated_type(typ): + return strip_annotated_type(cast(type, get_args(typ)[0])) + + return typ + + +def extract_type_arg(typ: type, index: int) -> type: + args = get_args(typ) + try: + return cast(type, args[index]) + except IndexError as err: + raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err + + +def extract_type_var_from_base( + typ: type, + *, + generic_bases: tuple[type, ...], + index: int, + failure_message: str | None = None, +) -> type: + """Given a type like `Foo[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyResponse(Foo[bytes]): + ... + + extract_type_var(MyResponse, bases=(Foo,), index=0) -> bytes + ``` + + And where a generic subclass is given: + ```py + _T = TypeVar('_T') + class MyResponse(Foo[_T]): + ... + + extract_type_var(MyResponse[bytes], bases=(Foo,), index=0) -> bytes + ``` + """ + cls = cast(object, get_origin(typ) or typ) + if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] + # we're given the class directly + return extract_type_arg(typ, index) + + # if a subclass is given + # --- + # this is needed as __orig_bases__ is not present in the typeshed stubs + # because it is intended to be for internal use only, however there does + # not seem to be a way to resolve generic TypeVars for inherited subclasses + # without using it. + if isinstance(cls, InheritsGeneric): + target_base_class: Any | None = None + for base in cls.__orig_bases__: + if base.__origin__ in generic_bases: + target_base_class = base + break + + if target_base_class is None: + raise RuntimeError( + "Could not find the generic base class;\n" + "This should never happen;\n" + f"Does {cls} inherit from one of {generic_bases} ?" + ) + + extracted = extract_type_arg(target_base_class, index) + if is_typevar(extracted): + # If the extracted type argument is itself a type variable + # then that means the subclass itself is generic, so we have + # to resolve the type argument from the class itself, not + # the base class. + # + # Note: if there is more than 1 type argument, the subclass could + # change the ordering of the type arguments, this is not currently + # supported. + return extract_type_arg(typ, index) + + return extracted + + raise RuntimeError(failure_message or f"Could not resolve inner type variable at index {index} for {typ}") diff --git a/src/gitpod/_utils/_utils.py b/src/gitpod/_utils/_utils.py new file mode 100644 index 0000000..ea3cf3f --- /dev/null +++ b/src/gitpod/_utils/_utils.py @@ -0,0 +1,422 @@ +from __future__ import annotations + +import os +import re +import inspect +import functools +from typing import ( + Any, + Tuple, + Mapping, + TypeVar, + Callable, + Iterable, + Sequence, + cast, + overload, +) +from pathlib import Path +from datetime import date, datetime +from typing_extensions import TypeGuard + +import sniffio + +from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike +from .._compat import parse_date as parse_date, parse_datetime as parse_datetime + +_T = TypeVar("_T") +_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) +_MappingT = TypeVar("_MappingT", bound=Mapping[str, object]) +_SequenceT = TypeVar("_SequenceT", bound=Sequence[object]) +CallableT = TypeVar("CallableT", bound=Callable[..., Any]) + + +def flatten(t: Iterable[Iterable[_T]]) -> list[_T]: + return [item for sublist in t for item in sublist] + + +def extract_files( + # TODO: this needs to take Dict but variance issues..... + # create protocol type ? + query: Mapping[str, object], + *, + paths: Sequence[Sequence[str]], +) -> list[tuple[str, FileTypes]]: + """Recursively extract files from the given dictionary based on specified paths. + + A path may look like this ['foo', 'files', '<array>', 'data']. + + Note: this mutates the given dictionary. + """ + files: list[tuple[str, FileTypes]] = [] + for path in paths: + files.extend(_extract_items(query, path, index=0, flattened_key=None)) + return files + + +def _extract_items( + obj: object, + path: Sequence[str], + *, + index: int, + flattened_key: str | None, +) -> list[tuple[str, FileTypes]]: + try: + key = path[index] + except IndexError: + if isinstance(obj, NotGiven): + # no value was provided - we can safely ignore + return [] + + # cyclical import + from .._files import assert_is_file_content + + # We have exhausted the path, return the entry we found. + assert flattened_key is not None + + if is_list(obj): + files: list[tuple[str, FileTypes]] = [] + for entry in obj: + assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "") + files.append((flattened_key + "[]", cast(FileTypes, entry))) + return files + + assert_is_file_content(obj, key=flattened_key) + return [(flattened_key, cast(FileTypes, obj))] + + index += 1 + if is_dict(obj): + try: + # We are at the last entry in the path so we must remove the field + if (len(path)) == index: + item = obj.pop(key) + else: + item = obj[key] + except KeyError: + # Key was not present in the dictionary, this is not indicative of an error + # as the given path may not point to a required field. We also do not want + # to enforce required fields as the API may differ from the spec in some cases. + return [] + if flattened_key is None: + flattened_key = key + else: + flattened_key += f"[{key}]" + return _extract_items( + item, + path, + index=index, + flattened_key=flattened_key, + ) + elif is_list(obj): + if key != "<array>": + return [] + + return flatten( + [ + _extract_items( + item, + path, + index=index, + flattened_key=flattened_key + "[]" if flattened_key is not None else "[]", + ) + for item in obj + ] + ) + + # Something unexpected was passed, just ignore it. + return [] + + +def is_given(obj: NotGivenOr[_T]) -> TypeGuard[_T]: + return not isinstance(obj, NotGiven) + + +# Type safe methods for narrowing types with TypeVars. +# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], +# however this cause Pyright to rightfully report errors. As we know we don't +# care about the contained types we can safely use `object` in it's place. +# +# There are two separate functions defined, `is_*` and `is_*_t` for different use cases. +# `is_*` is for when you're dealing with an unknown input +# `is_*_t` is for when you're narrowing a known union type to a specific subset + + +def is_tuple(obj: object) -> TypeGuard[tuple[object, ...]]: + return isinstance(obj, tuple) + + +def is_tuple_t(obj: _TupleT | object) -> TypeGuard[_TupleT]: + return isinstance(obj, tuple) + + +def is_sequence(obj: object) -> TypeGuard[Sequence[object]]: + return isinstance(obj, Sequence) + + +def is_sequence_t(obj: _SequenceT | object) -> TypeGuard[_SequenceT]: + return isinstance(obj, Sequence) + + +def is_mapping(obj: object) -> TypeGuard[Mapping[str, object]]: + return isinstance(obj, Mapping) + + +def is_mapping_t(obj: _MappingT | object) -> TypeGuard[_MappingT]: + return isinstance(obj, Mapping) + + +def is_dict(obj: object) -> TypeGuard[dict[object, object]]: + return isinstance(obj, dict) + + +def is_list(obj: object) -> TypeGuard[list[object]]: + return isinstance(obj, list) + + +def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: + return isinstance(obj, Iterable) + + +def deepcopy_minimal(item: _T) -> _T: + """Minimal reimplementation of copy.deepcopy() that will only copy certain object types: + + - mappings, e.g. `dict` + - list + + This is done for performance reasons. + """ + if is_mapping(item): + return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()}) + if is_list(item): + return cast(_T, [deepcopy_minimal(entry) for entry in item]) + return item + + +# copied from https://github.com/Rapptz/RoboDanny +def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: + size = len(seq) + if size == 0: + return "" + + if size == 1: + return seq[0] + + if size == 2: + return f"{seq[0]} {final} {seq[1]}" + + return delim.join(seq[:-1]) + f" {final} {seq[-1]}" + + +def quote(string: str) -> str: + """Add single quotation marks around the given string. Does *not* do any escaping.""" + return f"'{string}'" + + +def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]: + """Decorator to enforce a given set of arguments or variants of arguments are passed to the decorated function. + + Useful for enforcing runtime validation of overloaded functions. + + Example usage: + ```py + @overload + def foo(*, a: str) -> str: ... + + + @overload + def foo(*, b: bool) -> str: ... + + + # This enforces the same constraints that a static type checker would + # i.e. that either a or b must be passed to the function + @required_args(["a"], ["b"]) + def foo(*, a: str | None = None, b: bool | None = None) -> str: ... + ``` + """ + + def inner(func: CallableT) -> CallableT: + params = inspect.signature(func).parameters + positional = [ + name + for name, param in params.items() + if param.kind + in { + param.POSITIONAL_ONLY, + param.POSITIONAL_OR_KEYWORD, + } + ] + + @functools.wraps(func) + def wrapper(*args: object, **kwargs: object) -> object: + given_params: set[str] = set() + for i, _ in enumerate(args): + try: + given_params.add(positional[i]) + except IndexError: + raise TypeError( + f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given" + ) from None + + for key in kwargs.keys(): + given_params.add(key) + + for variant in variants: + matches = all((param in given_params for param in variant)) + if matches: + break + else: # no break + if len(variants) > 1: + variations = human_join( + ["(" + human_join([quote(arg) for arg in variant], final="and") + ")" for variant in variants] + ) + msg = f"Missing required arguments; Expected either {variations} arguments to be given" + else: + assert len(variants) > 0 + + # TODO: this error message is not deterministic + missing = list(set(variants[0]) - given_params) + if len(missing) > 1: + msg = f"Missing required arguments: {human_join([quote(arg) for arg in missing])}" + else: + msg = f"Missing required argument: {quote(missing[0])}" + raise TypeError(msg) + return func(*args, **kwargs) + + return wrapper # type: ignore + + return inner + + +_K = TypeVar("_K") +_V = TypeVar("_V") + + +@overload +def strip_not_given(obj: None) -> None: ... + + +@overload +def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: ... + + +@overload +def strip_not_given(obj: object) -> object: ... + + +def strip_not_given(obj: object | None) -> object: + """Remove all top-level keys where their values are instances of `NotGiven`""" + if obj is None: + return None + + if not is_mapping(obj): + return obj + + return {key: value for key, value in obj.items() if not isinstance(value, NotGiven)} + + +def coerce_integer(val: str) -> int: + return int(val, base=10) + + +def coerce_float(val: str) -> float: + return float(val) + + +def coerce_boolean(val: str) -> bool: + return val == "true" or val == "1" or val == "on" + + +def maybe_coerce_integer(val: str | None) -> int | None: + if val is None: + return None + return coerce_integer(val) + + +def maybe_coerce_float(val: str | None) -> float | None: + if val is None: + return None + return coerce_float(val) + + +def maybe_coerce_boolean(val: str | None) -> bool | None: + if val is None: + return None + return coerce_boolean(val) + + +def removeprefix(string: str, prefix: str) -> str: + """Remove a prefix from a string. + + Backport of `str.removeprefix` for Python < 3.9 + """ + if string.startswith(prefix): + return string[len(prefix) :] + return string + + +def removesuffix(string: str, suffix: str) -> str: + """Remove a suffix from a string. + + Backport of `str.removesuffix` for Python < 3.9 + """ + if string.endswith(suffix): + return string[: -len(suffix)] + return string + + +def file_from_path(path: str) -> FileTypes: + contents = Path(path).read_bytes() + file_name = os.path.basename(path) + return (file_name, contents) + + +def get_required_header(headers: HeadersLike, header: str) -> str: + lower_header = header.lower() + if is_mapping_t(headers): + # mypy doesn't understand the type narrowing here + for k, v in headers.items(): # type: ignore + if k.lower() == lower_header and isinstance(v, str): + return v + + # to deal with the case where the header looks like Stainless-Event-Id + intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) + + for normalized_header in [header, lower_header, header.upper(), intercaps_header]: + value = headers.get(normalized_header) + if value: + return value + + raise ValueError(f"Could not find {header} header") + + +def get_async_library() -> str: + try: + return sniffio.current_async_library() + except Exception: + return "false" + + +def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: + """A version of functools.lru_cache that retains the type signature + for the wrapped function arguments. + """ + wrapper = functools.lru_cache( # noqa: TID251 + maxsize=maxsize, + ) + return cast(Any, wrapper) # type: ignore[no-any-return] + + +def json_safe(data: object) -> object: + """Translates a mapping / sequence recursively in the same fashion + as `pydantic` v2's `model_dump(mode="json")`. + """ + if is_mapping(data): + return {json_safe(key): json_safe(value) for key, value in data.items()} + + if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)): + return [json_safe(item) for item in data] + + if isinstance(data, (datetime, date)): + return data.isoformat() + + return data diff --git a/src/gitpod/_version.py b/src/gitpod/_version.py new file mode 100644 index 0000000..1bd510f --- /dev/null +++ b/src/gitpod/_version.py @@ -0,0 +1,4 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +__title__ = "gitpod" +__version__ = "0.3.0" # x-release-please-version diff --git a/src/gitpod/lib/.keep b/src/gitpod/lib/.keep new file mode 100644 index 0000000..5e2c99f --- /dev/null +++ b/src/gitpod/lib/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store custom files to expand the SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/src/gitpod/pagination.py b/src/gitpod/pagination.py new file mode 100644 index 0000000..647ccd9 --- /dev/null +++ b/src/gitpod/pagination.py @@ -0,0 +1,1127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Generic, TypeVar, Optional +from typing_extensions import override + +from pydantic import Field as FieldInfo + +from ._models import BaseModel +from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage + +__all__ = [ + "DomainVerificationsPagePagination", + "SyncDomainVerificationsPage", + "AsyncDomainVerificationsPage", + "EditorsPagePagination", + "SyncEditorsPage", + "AsyncEditorsPage", + "EntriesPagePagination", + "SyncEntriesPage", + "AsyncEntriesPage", + "EnvironmentClassesPagePagination", + "SyncEnvironmentClassesPage", + "AsyncEnvironmentClassesPage", + "EnvironmentsPagePagination", + "SyncEnvironmentsPage", + "AsyncEnvironmentsPage", + "GatewaysPagePagination", + "SyncGatewaysPage", + "AsyncGatewaysPage", + "GroupsPagePagination", + "SyncGroupsPage", + "AsyncGroupsPage", + "IntegrationsPagePagination", + "SyncIntegrationsPage", + "AsyncIntegrationsPage", + "LoginProvidersPagePagination", + "SyncLoginProvidersPage", + "AsyncLoginProvidersPage", + "MembersPagePagination", + "SyncMembersPage", + "AsyncMembersPage", + "PersonalAccessTokensPagePagination", + "SyncPersonalAccessTokensPage", + "AsyncPersonalAccessTokensPage", + "PoliciesPagePagination", + "SyncPoliciesPage", + "AsyncPoliciesPage", + "ProjectsPagePagination", + "SyncProjectsPage", + "AsyncProjectsPage", + "RecordsPagePagination", + "SyncRecordsPage", + "AsyncRecordsPage", + "RunnersPagePagination", + "SyncRunnersPage", + "AsyncRunnersPage", + "SecretsPagePagination", + "SyncSecretsPage", + "AsyncSecretsPage", + "ServicesPagePagination", + "SyncServicesPage", + "AsyncServicesPage", + "SSOConfigurationsPagePagination", + "SyncSSOConfigurationsPage", + "AsyncSSOConfigurationsPage", + "TaskExecutionsPagePagination", + "SyncTaskExecutionsPage", + "AsyncTaskExecutionsPage", + "TasksPagePagination", + "SyncTasksPage", + "AsyncTasksPage", + "TokensPagePagination", + "SyncTokensPage", + "AsyncTokensPage", +] + +_T = TypeVar("_T") + + +class DomainVerificationsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncDomainVerificationsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + domain_verifications: List[_T] = FieldInfo(alias="domainVerifications") + pagination: Optional[DomainVerificationsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + domain_verifications = self.domain_verifications + if not domain_verifications: + return [] + return domain_verifications + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncDomainVerificationsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + domain_verifications: List[_T] = FieldInfo(alias="domainVerifications") + pagination: Optional[DomainVerificationsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + domain_verifications = self.domain_verifications + if not domain_verifications: + return [] + return domain_verifications + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class EditorsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncEditorsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + editors: List[_T] + pagination: Optional[EditorsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + editors = self.editors + if not editors: + return [] + return editors + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncEditorsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + editors: List[_T] + pagination: Optional[EditorsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + editors = self.editors + if not editors: + return [] + return editors + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class EntriesPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncEntriesPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + entries: List[_T] + pagination: Optional[EntriesPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + entries = self.entries + if not entries: + return [] + return entries + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncEntriesPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + entries: List[_T] + pagination: Optional[EntriesPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + entries = self.entries + if not entries: + return [] + return entries + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class EnvironmentClassesPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncEnvironmentClassesPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + environment_classes: List[_T] = FieldInfo(alias="environmentClasses") + pagination: Optional[EnvironmentClassesPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + environment_classes = self.environment_classes + if not environment_classes: + return [] + return environment_classes + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncEnvironmentClassesPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + environment_classes: List[_T] = FieldInfo(alias="environmentClasses") + pagination: Optional[EnvironmentClassesPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + environment_classes = self.environment_classes + if not environment_classes: + return [] + return environment_classes + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class EnvironmentsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncEnvironmentsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + environments: List[_T] + pagination: Optional[EnvironmentsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + environments = self.environments + if not environments: + return [] + return environments + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncEnvironmentsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + environments: List[_T] + pagination: Optional[EnvironmentsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + environments = self.environments + if not environments: + return [] + return environments + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class GatewaysPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncGatewaysPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + gateways: List[_T] + pagination: Optional[GatewaysPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + gateways = self.gateways + if not gateways: + return [] + return gateways + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncGatewaysPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + gateways: List[_T] + pagination: Optional[GatewaysPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + gateways = self.gateways + if not gateways: + return [] + return gateways + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class GroupsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncGroupsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + groups: List[_T] + pagination: Optional[GroupsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + groups = self.groups + if not groups: + return [] + return groups + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncGroupsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + groups: List[_T] + pagination: Optional[GroupsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + groups = self.groups + if not groups: + return [] + return groups + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class IntegrationsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncIntegrationsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + integrations: List[_T] + pagination: Optional[IntegrationsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + integrations = self.integrations + if not integrations: + return [] + return integrations + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncIntegrationsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + integrations: List[_T] + pagination: Optional[IntegrationsPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + integrations = self.integrations + if not integrations: + return [] + return integrations + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class LoginProvidersPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncLoginProvidersPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + login_providers: List[_T] = FieldInfo(alias="loginProviders") + pagination: Optional[LoginProvidersPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + login_providers = self.login_providers + if not login_providers: + return [] + return login_providers + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncLoginProvidersPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + login_providers: List[_T] = FieldInfo(alias="loginProviders") + pagination: Optional[LoginProvidersPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + login_providers = self.login_providers + if not login_providers: + return [] + return login_providers + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class MembersPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncMembersPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + members: List[_T] + pagination: Optional[MembersPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + members = self.members + if not members: + return [] + return members + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncMembersPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + members: List[_T] + pagination: Optional[MembersPagePagination] = None + + @override + def _get_page_items(self) -> List[_T]: + members = self.members + if not members: + return [] + return members + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class PersonalAccessTokensPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncPersonalAccessTokensPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[PersonalAccessTokensPagePagination] = None + personal_access_tokens: List[_T] = FieldInfo(alias="personalAccessTokens") + + @override + def _get_page_items(self) -> List[_T]: + personal_access_tokens = self.personal_access_tokens + if not personal_access_tokens: + return [] + return personal_access_tokens + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncPersonalAccessTokensPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[PersonalAccessTokensPagePagination] = None + personal_access_tokens: List[_T] = FieldInfo(alias="personalAccessTokens") + + @override + def _get_page_items(self) -> List[_T]: + personal_access_tokens = self.personal_access_tokens + if not personal_access_tokens: + return [] + return personal_access_tokens + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class PoliciesPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncPoliciesPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[PoliciesPagePagination] = None + policies: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + policies = self.policies + if not policies: + return [] + return policies + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncPoliciesPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[PoliciesPagePagination] = None + policies: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + policies = self.policies + if not policies: + return [] + return policies + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class ProjectsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncProjectsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[ProjectsPagePagination] = None + projects: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + projects = self.projects + if not projects: + return [] + return projects + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncProjectsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[ProjectsPagePagination] = None + projects: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + projects = self.projects + if not projects: + return [] + return projects + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class RecordsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncRecordsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[RecordsPagePagination] = None + records: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + records = self.records + if not records: + return [] + return records + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncRecordsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[RecordsPagePagination] = None + records: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + records = self.records + if not records: + return [] + return records + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class RunnersPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncRunnersPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[RunnersPagePagination] = None + runners: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + runners = self.runners + if not runners: + return [] + return runners + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncRunnersPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[RunnersPagePagination] = None + runners: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + runners = self.runners + if not runners: + return [] + return runners + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class SecretsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncSecretsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[SecretsPagePagination] = None + secrets: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + secrets = self.secrets + if not secrets: + return [] + return secrets + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncSecretsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[SecretsPagePagination] = None + secrets: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + secrets = self.secrets + if not secrets: + return [] + return secrets + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class ServicesPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncServicesPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[ServicesPagePagination] = None + services: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + services = self.services + if not services: + return [] + return services + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncServicesPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[ServicesPagePagination] = None + services: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + services = self.services + if not services: + return [] + return services + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class SSOConfigurationsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncSSOConfigurationsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[SSOConfigurationsPagePagination] = None + sso_configurations: List[_T] = FieldInfo(alias="ssoConfigurations") + + @override + def _get_page_items(self) -> List[_T]: + sso_configurations = self.sso_configurations + if not sso_configurations: + return [] + return sso_configurations + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncSSOConfigurationsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[SSOConfigurationsPagePagination] = None + sso_configurations: List[_T] = FieldInfo(alias="ssoConfigurations") + + @override + def _get_page_items(self) -> List[_T]: + sso_configurations = self.sso_configurations + if not sso_configurations: + return [] + return sso_configurations + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class TaskExecutionsPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncTaskExecutionsPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[TaskExecutionsPagePagination] = None + task_executions: List[_T] = FieldInfo(alias="taskExecutions") + + @override + def _get_page_items(self) -> List[_T]: + task_executions = self.task_executions + if not task_executions: + return [] + return task_executions + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncTaskExecutionsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[TaskExecutionsPagePagination] = None + task_executions: List[_T] = FieldInfo(alias="taskExecutions") + + @override + def _get_page_items(self) -> List[_T]: + task_executions = self.task_executions + if not task_executions: + return [] + return task_executions + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class TasksPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncTasksPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[TasksPagePagination] = None + tasks: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + tasks = self.tasks + if not tasks: + return [] + return tasks + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncTasksPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[TasksPagePagination] = None + tasks: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + tasks = self.tasks + if not tasks: + return [] + return tasks + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class TokensPagePagination(BaseModel): + next_token: Optional[str] = FieldInfo(alias="nextToken", default=None) + + +class SyncTokensPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[TokensPagePagination] = None + tokens: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + tokens = self.tokens + if not tokens: + return [] + return tokens + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) + + +class AsyncTokensPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + pagination: Optional[TokensPagePagination] = None + tokens: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + tokens = self.tokens + if not tokens: + return [] + return tokens + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_token = None + if self.pagination is not None: + if self.pagination.next_token is not None: + next_token = self.pagination.next_token + if not next_token: + return None + + return PageInfo(params={"token": next_token}) diff --git a/src/gitpod/py.typed b/src/gitpod/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/src/gitpod/resources/__init__.py b/src/gitpod/resources/__init__.py new file mode 100644 index 0000000..fe63612 --- /dev/null +++ b/src/gitpod/resources/__init__.py @@ -0,0 +1,187 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .usage import ( + UsageResource, + AsyncUsageResource, + UsageResourceWithRawResponse, + AsyncUsageResourceWithRawResponse, + UsageResourceWithStreamingResponse, + AsyncUsageResourceWithStreamingResponse, +) +from .users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from .events import ( + EventsResource, + AsyncEventsResource, + EventsResourceWithRawResponse, + AsyncEventsResourceWithRawResponse, + EventsResourceWithStreamingResponse, + AsyncEventsResourceWithStreamingResponse, +) +from .groups import ( + GroupsResource, + AsyncGroupsResource, + GroupsResourceWithRawResponse, + AsyncGroupsResourceWithRawResponse, + GroupsResourceWithStreamingResponse, + AsyncGroupsResourceWithStreamingResponse, +) +from .editors import ( + EditorsResource, + AsyncEditorsResource, + EditorsResourceWithRawResponse, + AsyncEditorsResourceWithRawResponse, + EditorsResourceWithStreamingResponse, + AsyncEditorsResourceWithStreamingResponse, +) +from .runners import ( + RunnersResource, + AsyncRunnersResource, + RunnersResourceWithRawResponse, + AsyncRunnersResourceWithRawResponse, + RunnersResourceWithStreamingResponse, + AsyncRunnersResourceWithStreamingResponse, +) +from .secrets import ( + SecretsResource, + AsyncSecretsResource, + SecretsResourceWithRawResponse, + AsyncSecretsResourceWithRawResponse, + SecretsResourceWithStreamingResponse, + AsyncSecretsResourceWithStreamingResponse, +) +from .accounts import ( + AccountsResource, + AsyncAccountsResource, + AccountsResourceWithRawResponse, + AsyncAccountsResourceWithRawResponse, + AccountsResourceWithStreamingResponse, + AsyncAccountsResourceWithStreamingResponse, +) +from .gateways import ( + GatewaysResource, + AsyncGatewaysResource, + GatewaysResourceWithRawResponse, + AsyncGatewaysResourceWithRawResponse, + GatewaysResourceWithStreamingResponse, + AsyncGatewaysResourceWithStreamingResponse, +) +from .identity import ( + IdentityResource, + AsyncIdentityResource, + IdentityResourceWithRawResponse, + AsyncIdentityResourceWithRawResponse, + IdentityResourceWithStreamingResponse, + AsyncIdentityResourceWithStreamingResponse, +) +from .projects import ( + ProjectsResource, + AsyncProjectsResource, + ProjectsResourceWithRawResponse, + AsyncProjectsResourceWithRawResponse, + ProjectsResourceWithStreamingResponse, + AsyncProjectsResourceWithStreamingResponse, +) +from .environments import ( + EnvironmentsResource, + AsyncEnvironmentsResource, + EnvironmentsResourceWithRawResponse, + AsyncEnvironmentsResourceWithRawResponse, + EnvironmentsResourceWithStreamingResponse, + AsyncEnvironmentsResourceWithStreamingResponse, +) +from .organizations import ( + OrganizationsResource, + AsyncOrganizationsResource, + OrganizationsResourceWithRawResponse, + AsyncOrganizationsResourceWithRawResponse, + OrganizationsResourceWithStreamingResponse, + AsyncOrganizationsResourceWithStreamingResponse, +) + +__all__ = [ + "AccountsResource", + "AsyncAccountsResource", + "AccountsResourceWithRawResponse", + "AsyncAccountsResourceWithRawResponse", + "AccountsResourceWithStreamingResponse", + "AsyncAccountsResourceWithStreamingResponse", + "EditorsResource", + "AsyncEditorsResource", + "EditorsResourceWithRawResponse", + "AsyncEditorsResourceWithRawResponse", + "EditorsResourceWithStreamingResponse", + "AsyncEditorsResourceWithStreamingResponse", + "EnvironmentsResource", + "AsyncEnvironmentsResource", + "EnvironmentsResourceWithRawResponse", + "AsyncEnvironmentsResourceWithRawResponse", + "EnvironmentsResourceWithStreamingResponse", + "AsyncEnvironmentsResourceWithStreamingResponse", + "EventsResource", + "AsyncEventsResource", + "EventsResourceWithRawResponse", + "AsyncEventsResourceWithRawResponse", + "EventsResourceWithStreamingResponse", + "AsyncEventsResourceWithStreamingResponse", + "GatewaysResource", + "AsyncGatewaysResource", + "GatewaysResourceWithRawResponse", + "AsyncGatewaysResourceWithRawResponse", + "GatewaysResourceWithStreamingResponse", + "AsyncGatewaysResourceWithStreamingResponse", + "GroupsResource", + "AsyncGroupsResource", + "GroupsResourceWithRawResponse", + "AsyncGroupsResourceWithRawResponse", + "GroupsResourceWithStreamingResponse", + "AsyncGroupsResourceWithStreamingResponse", + "IdentityResource", + "AsyncIdentityResource", + "IdentityResourceWithRawResponse", + "AsyncIdentityResourceWithRawResponse", + "IdentityResourceWithStreamingResponse", + "AsyncIdentityResourceWithStreamingResponse", + "OrganizationsResource", + "AsyncOrganizationsResource", + "OrganizationsResourceWithRawResponse", + "AsyncOrganizationsResourceWithRawResponse", + "OrganizationsResourceWithStreamingResponse", + "AsyncOrganizationsResourceWithStreamingResponse", + "ProjectsResource", + "AsyncProjectsResource", + "ProjectsResourceWithRawResponse", + "AsyncProjectsResourceWithRawResponse", + "ProjectsResourceWithStreamingResponse", + "AsyncProjectsResourceWithStreamingResponse", + "RunnersResource", + "AsyncRunnersResource", + "RunnersResourceWithRawResponse", + "AsyncRunnersResourceWithRawResponse", + "RunnersResourceWithStreamingResponse", + "AsyncRunnersResourceWithStreamingResponse", + "SecretsResource", + "AsyncSecretsResource", + "SecretsResourceWithRawResponse", + "AsyncSecretsResourceWithRawResponse", + "SecretsResourceWithStreamingResponse", + "AsyncSecretsResourceWithStreamingResponse", + "UsageResource", + "AsyncUsageResource", + "UsageResourceWithRawResponse", + "AsyncUsageResourceWithRawResponse", + "UsageResourceWithStreamingResponse", + "AsyncUsageResourceWithStreamingResponse", + "UsersResource", + "AsyncUsersResource", + "UsersResourceWithRawResponse", + "AsyncUsersResourceWithRawResponse", + "UsersResourceWithStreamingResponse", + "AsyncUsersResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/accounts.py b/src/gitpod/resources/accounts.py new file mode 100644 index 0000000..e756632 --- /dev/null +++ b/src/gitpod/resources/accounts.py @@ -0,0 +1,787 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ..types import ( + account_delete_params, + account_retrieve_params, + account_get_sso_login_url_params, + account_list_login_providers_params, + account_list_joinable_organizations_params, +) +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncLoginProvidersPage, AsyncLoginProvidersPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.login_provider import LoginProvider +from ..types.account_retrieve_response import AccountRetrieveResponse +from ..types.account_get_sso_login_url_response import AccountGetSSOLoginURLResponse +from ..types.account_list_joinable_organizations_response import AccountListJoinableOrganizationsResponse + +__all__ = ["AccountsResource", "AsyncAccountsResource"] + + +class AccountsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AccountsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AccountsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AccountsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AccountsResourceWithStreamingResponse(self) + + def retrieve( + self, + *, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> AccountRetrieveResponse: + """ + Gets information about the currently authenticated account. + + Use this method to: + + - Retrieve account profile information + - Check organization memberships + - View account settings + - Get joinable organizations + + ### Examples + + - Get account details: + + Retrieves information about the authenticated account. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.AccountService/GetAccount", + body=maybe_transform({"empty": empty}, account_retrieve_params.AccountRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccountRetrieveResponse, + ) + + def delete( + self, + *, + account_id: str, + # 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, + ) -> object: + """ + Deletes an account permanently. + + Use this method to: + + - Remove unused accounts + - Clean up test accounts + - Complete account deletion requests + + The account must not be an active member of any organization. + + ### Examples + + - Delete account: + + Permanently removes an account. + + ```yaml + accountId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.AccountService/DeleteAccount", + body=maybe_transform({"account_id": account_id}, account_delete_params.AccountDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def get_sso_login_url( + self, + *, + email: str, + return_to: Optional[str] | NotGiven = NOT_GIVEN, + # 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, + ) -> AccountGetSSOLoginURLResponse: + """ + Gets the SSO login URL for a specific email domain. + + Use this method to: + + - Initiate SSO authentication + - Get organization-specific login URLs + - Handle SSO redirects + + ### Examples + + - Get login URL: + + Retrieves SSO URL for email domain. + + ```yaml + email: "user@company.com" + ``` + + - Get URL with return path: + + Gets SSO URL with specific return location. + + ```yaml + email: "user@company.com" + returnTo: "https://gitpod.io/workspaces" + ``` + + Args: + email: email is the email the user wants to login with + + return_to: return_to is the URL the user will be redirected to after login + + 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.AccountService/GetSSOLoginURL", + body=maybe_transform( + { + "email": email, + "return_to": return_to, + }, + account_get_sso_login_url_params.AccountGetSSOLoginURLParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccountGetSSOLoginURLResponse, + ) + + def list_joinable_organizations( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> AccountListJoinableOrganizationsResponse: + """ + Lists organizations that the currently authenticated account can join. + + Use this method to: + + - Discover organizations associated with the account's email domain. + - Allow users to join existing organizations. + - Display potential organizations during onboarding. + + ### Examples + + - List joinable organizations: + + Retrieves a list of organizations the account can join. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.AccountService/ListJoinableOrganizations", + body=maybe_transform( + {"empty": empty}, account_list_joinable_organizations_params.AccountListJoinableOrganizationsParams + ), + 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, + }, + account_list_joinable_organizations_params.AccountListJoinableOrganizationsParams, + ), + ), + cast_to=AccountListJoinableOrganizationsResponse, + ) + + def list_login_providers( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: account_list_login_providers_params.Filter | NotGiven = NOT_GIVEN, + pagination: account_list_login_providers_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncLoginProvidersPage[LoginProvider]: + """ + Lists available login providers with optional filtering. + + Use this method to: + + - View supported authentication methods + - Get provider-specific login URLs + - Filter providers by invite + + ### Examples + + - List all providers: + + Shows all available login providers. + + ```yaml + pagination: + pageSize: 20 + ``` + + - List for specific invite: + + Shows providers available for an invite. + + ```yaml + filter: + inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + pagination: + pageSize: 20 + ``` + + Args: + filter: filter contains the filter options for listing login methods + + pagination: pagination contains the pagination options for listing login methods + + 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._get_api_list( + "/gitpod.v1.AccountService/ListLoginProviders", + page=SyncLoginProvidersPage[LoginProvider], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + account_list_login_providers_params.AccountListLoginProvidersParams, + ), + 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, + }, + account_list_login_providers_params.AccountListLoginProvidersParams, + ), + ), + model=LoginProvider, + method="post", + ) + + +class AsyncAccountsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAccountsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncAccountsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAccountsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncAccountsResourceWithStreamingResponse(self) + + async def retrieve( + self, + *, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> AccountRetrieveResponse: + """ + Gets information about the currently authenticated account. + + Use this method to: + + - Retrieve account profile information + - Check organization memberships + - View account settings + - Get joinable organizations + + ### Examples + + - Get account details: + + Retrieves information about the authenticated account. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.AccountService/GetAccount", + body=await async_maybe_transform({"empty": empty}, account_retrieve_params.AccountRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccountRetrieveResponse, + ) + + async def delete( + self, + *, + account_id: str, + # 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, + ) -> object: + """ + Deletes an account permanently. + + Use this method to: + + - Remove unused accounts + - Clean up test accounts + - Complete account deletion requests + + The account must not be an active member of any organization. + + ### Examples + + - Delete account: + + Permanently removes an account. + + ```yaml + accountId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.AccountService/DeleteAccount", + body=await async_maybe_transform({"account_id": account_id}, account_delete_params.AccountDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def get_sso_login_url( + self, + *, + email: str, + return_to: Optional[str] | NotGiven = NOT_GIVEN, + # 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, + ) -> AccountGetSSOLoginURLResponse: + """ + Gets the SSO login URL for a specific email domain. + + Use this method to: + + - Initiate SSO authentication + - Get organization-specific login URLs + - Handle SSO redirects + + ### Examples + + - Get login URL: + + Retrieves SSO URL for email domain. + + ```yaml + email: "user@company.com" + ``` + + - Get URL with return path: + + Gets SSO URL with specific return location. + + ```yaml + email: "user@company.com" + returnTo: "https://gitpod.io/workspaces" + ``` + + Args: + email: email is the email the user wants to login with + + return_to: return_to is the URL the user will be redirected to after login + + 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.AccountService/GetSSOLoginURL", + body=await async_maybe_transform( + { + "email": email, + "return_to": return_to, + }, + account_get_sso_login_url_params.AccountGetSSOLoginURLParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccountGetSSOLoginURLResponse, + ) + + async def list_joinable_organizations( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> AccountListJoinableOrganizationsResponse: + """ + Lists organizations that the currently authenticated account can join. + + Use this method to: + + - Discover organizations associated with the account's email domain. + - Allow users to join existing organizations. + - Display potential organizations during onboarding. + + ### Examples + + - List joinable organizations: + + Retrieves a list of organizations the account can join. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.AccountService/ListJoinableOrganizations", + body=await async_maybe_transform( + {"empty": empty}, account_list_joinable_organizations_params.AccountListJoinableOrganizationsParams + ), + 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, + }, + account_list_joinable_organizations_params.AccountListJoinableOrganizationsParams, + ), + ), + cast_to=AccountListJoinableOrganizationsResponse, + ) + + def list_login_providers( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: account_list_login_providers_params.Filter | NotGiven = NOT_GIVEN, + pagination: account_list_login_providers_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[LoginProvider, AsyncLoginProvidersPage[LoginProvider]]: + """ + Lists available login providers with optional filtering. + + Use this method to: + + - View supported authentication methods + - Get provider-specific login URLs + - Filter providers by invite + + ### Examples + + - List all providers: + + Shows all available login providers. + + ```yaml + pagination: + pageSize: 20 + ``` + + - List for specific invite: + + Shows providers available for an invite. + + ```yaml + filter: + inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + pagination: + pageSize: 20 + ``` + + Args: + filter: filter contains the filter options for listing login methods + + pagination: pagination contains the pagination options for listing login methods + + 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._get_api_list( + "/gitpod.v1.AccountService/ListLoginProviders", + page=AsyncLoginProvidersPage[LoginProvider], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + account_list_login_providers_params.AccountListLoginProvidersParams, + ), + 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, + }, + account_list_login_providers_params.AccountListLoginProvidersParams, + ), + ), + model=LoginProvider, + method="post", + ) + + +class AccountsResourceWithRawResponse: + def __init__(self, accounts: AccountsResource) -> None: + self._accounts = accounts + + self.retrieve = to_raw_response_wrapper( + accounts.retrieve, + ) + self.delete = to_raw_response_wrapper( + accounts.delete, + ) + self.get_sso_login_url = to_raw_response_wrapper( + accounts.get_sso_login_url, + ) + self.list_joinable_organizations = to_raw_response_wrapper( + accounts.list_joinable_organizations, + ) + self.list_login_providers = to_raw_response_wrapper( + accounts.list_login_providers, + ) + + +class AsyncAccountsResourceWithRawResponse: + def __init__(self, accounts: AsyncAccountsResource) -> None: + self._accounts = accounts + + self.retrieve = async_to_raw_response_wrapper( + accounts.retrieve, + ) + self.delete = async_to_raw_response_wrapper( + accounts.delete, + ) + self.get_sso_login_url = async_to_raw_response_wrapper( + accounts.get_sso_login_url, + ) + self.list_joinable_organizations = async_to_raw_response_wrapper( + accounts.list_joinable_organizations, + ) + self.list_login_providers = async_to_raw_response_wrapper( + accounts.list_login_providers, + ) + + +class AccountsResourceWithStreamingResponse: + def __init__(self, accounts: AccountsResource) -> None: + self._accounts = accounts + + self.retrieve = to_streamed_response_wrapper( + accounts.retrieve, + ) + self.delete = to_streamed_response_wrapper( + accounts.delete, + ) + self.get_sso_login_url = to_streamed_response_wrapper( + accounts.get_sso_login_url, + ) + self.list_joinable_organizations = to_streamed_response_wrapper( + accounts.list_joinable_organizations, + ) + self.list_login_providers = to_streamed_response_wrapper( + accounts.list_login_providers, + ) + + +class AsyncAccountsResourceWithStreamingResponse: + def __init__(self, accounts: AsyncAccountsResource) -> None: + self._accounts = accounts + + self.retrieve = async_to_streamed_response_wrapper( + accounts.retrieve, + ) + self.delete = async_to_streamed_response_wrapper( + accounts.delete, + ) + self.get_sso_login_url = async_to_streamed_response_wrapper( + accounts.get_sso_login_url, + ) + self.list_joinable_organizations = async_to_streamed_response_wrapper( + accounts.list_joinable_organizations, + ) + self.list_login_providers = async_to_streamed_response_wrapper( + accounts.list_login_providers, + ) diff --git a/src/gitpod/resources/editors.py b/src/gitpod/resources/editors.py new file mode 100644 index 0000000..3c3075f --- /dev/null +++ b/src/gitpod/resources/editors.py @@ -0,0 +1,532 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import editor_list_params, editor_retrieve_params, editor_resolve_url_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncEditorsPage, AsyncEditorsPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.editor import Editor +from ..types.editor_retrieve_response import EditorRetrieveResponse +from ..types.editor_resolve_url_response import EditorResolveURLResponse + +__all__ = ["EditorsResource", "AsyncEditorsResource"] + + +class EditorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> EditorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return EditorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> EditorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return EditorsResourceWithStreamingResponse(self) + + def retrieve( + self, + *, + id: str, + # 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, + ) -> EditorRetrieveResponse: + """ + Gets details about a specific editor. + + Use this method to: + + - View editor information + - Get editor configuration + + ### Examples + + - Get editor details: + + Retrieves information about a specific editor. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + id: id is the ID of the editor to get + + 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.EditorService/GetEditor", + body=maybe_transform({"id": id}, editor_retrieve_params.EditorRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EditorRetrieveResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: editor_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: editor_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncEditorsPage[Editor]: + """ + Lists all available code editors, optionally filtered to those allowed in an + organization. + + Use this method to: + + - View supported editors + - Get editor capabilities + - Browse editor options + - Check editor availability + + ### Examples + + - List editors: + + Shows all available editors with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + - List editors available to the organization: + + Shows all available editors that are allowed by the policies enforced in the + organization with pagination. + + ```yaml + pagination: + pageSize: 20 + filter: + allowedByPolicy: true + ``` + + Args: + filter: filter contains the filter options for listing editors + + pagination: pagination contains the pagination options for listing environments + + 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._get_api_list( + "/gitpod.v1.EditorService/ListEditors", + page=SyncEditorsPage[Editor], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + editor_list_params.EditorListParams, + ), + 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, + }, + editor_list_params.EditorListParams, + ), + ), + model=Editor, + method="post", + ) + + def resolve_url( + self, + *, + editor_id: str, + environment_id: str, + organization_id: str, + # 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, + ) -> EditorResolveURLResponse: + """ + Resolves the URL for accessing an editor in a specific environment. + + Use this method to: + + - Get editor access URLs + - Launch editors for environments + - Set up editor connections + - Configure editor access + + ### Examples + + - Resolve editor URL: + + Gets the URL for accessing an editor in an environment. + + ```yaml + editorId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + editor_id: editorId is the ID of the editor to resolve the URL for + + environment_id: environmentId is the ID of the environment to resolve the URL for + + organization_id: organizationId is the ID of the organization to resolve the URL 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.EditorService/ResolveEditorURL", + body=maybe_transform( + { + "editor_id": editor_id, + "environment_id": environment_id, + "organization_id": organization_id, + }, + editor_resolve_url_params.EditorResolveURLParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EditorResolveURLResponse, + ) + + +class AsyncEditorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncEditorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncEditorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncEditorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncEditorsResourceWithStreamingResponse(self) + + async def retrieve( + self, + *, + id: str, + # 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, + ) -> EditorRetrieveResponse: + """ + Gets details about a specific editor. + + Use this method to: + + - View editor information + - Get editor configuration + + ### Examples + + - Get editor details: + + Retrieves information about a specific editor. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + id: id is the ID of the editor to get + + 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.EditorService/GetEditor", + body=await async_maybe_transform({"id": id}, editor_retrieve_params.EditorRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EditorRetrieveResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: editor_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: editor_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Editor, AsyncEditorsPage[Editor]]: + """ + Lists all available code editors, optionally filtered to those allowed in an + organization. + + Use this method to: + + - View supported editors + - Get editor capabilities + - Browse editor options + - Check editor availability + + ### Examples + + - List editors: + + Shows all available editors with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + - List editors available to the organization: + + Shows all available editors that are allowed by the policies enforced in the + organization with pagination. + + ```yaml + pagination: + pageSize: 20 + filter: + allowedByPolicy: true + ``` + + Args: + filter: filter contains the filter options for listing editors + + pagination: pagination contains the pagination options for listing environments + + 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._get_api_list( + "/gitpod.v1.EditorService/ListEditors", + page=AsyncEditorsPage[Editor], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + editor_list_params.EditorListParams, + ), + 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, + }, + editor_list_params.EditorListParams, + ), + ), + model=Editor, + method="post", + ) + + async def resolve_url( + self, + *, + editor_id: str, + environment_id: str, + organization_id: str, + # 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, + ) -> EditorResolveURLResponse: + """ + Resolves the URL for accessing an editor in a specific environment. + + Use this method to: + + - Get editor access URLs + - Launch editors for environments + - Set up editor connections + - Configure editor access + + ### Examples + + - Resolve editor URL: + + Gets the URL for accessing an editor in an environment. + + ```yaml + editorId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + editor_id: editorId is the ID of the editor to resolve the URL for + + environment_id: environmentId is the ID of the environment to resolve the URL for + + organization_id: organizationId is the ID of the organization to resolve the URL 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.EditorService/ResolveEditorURL", + body=await async_maybe_transform( + { + "editor_id": editor_id, + "environment_id": environment_id, + "organization_id": organization_id, + }, + editor_resolve_url_params.EditorResolveURLParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EditorResolveURLResponse, + ) + + +class EditorsResourceWithRawResponse: + def __init__(self, editors: EditorsResource) -> None: + self._editors = editors + + self.retrieve = to_raw_response_wrapper( + editors.retrieve, + ) + self.list = to_raw_response_wrapper( + editors.list, + ) + self.resolve_url = to_raw_response_wrapper( + editors.resolve_url, + ) + + +class AsyncEditorsResourceWithRawResponse: + def __init__(self, editors: AsyncEditorsResource) -> None: + self._editors = editors + + self.retrieve = async_to_raw_response_wrapper( + editors.retrieve, + ) + self.list = async_to_raw_response_wrapper( + editors.list, + ) + self.resolve_url = async_to_raw_response_wrapper( + editors.resolve_url, + ) + + +class EditorsResourceWithStreamingResponse: + def __init__(self, editors: EditorsResource) -> None: + self._editors = editors + + self.retrieve = to_streamed_response_wrapper( + editors.retrieve, + ) + self.list = to_streamed_response_wrapper( + editors.list, + ) + self.resolve_url = to_streamed_response_wrapper( + editors.resolve_url, + ) + + +class AsyncEditorsResourceWithStreamingResponse: + def __init__(self, editors: AsyncEditorsResource) -> None: + self._editors = editors + + self.retrieve = async_to_streamed_response_wrapper( + editors.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + editors.list, + ) + self.resolve_url = async_to_streamed_response_wrapper( + editors.resolve_url, + ) diff --git a/src/gitpod/resources/environments/__init__.py b/src/gitpod/resources/environments/__init__.py new file mode 100644 index 0000000..854ce71 --- /dev/null +++ b/src/gitpod/resources/environments/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .classes import ( + ClassesResource, + AsyncClassesResource, + ClassesResourceWithRawResponse, + AsyncClassesResourceWithRawResponse, + ClassesResourceWithStreamingResponse, + AsyncClassesResourceWithStreamingResponse, +) +from .automations import ( + AutomationsResource, + AsyncAutomationsResource, + AutomationsResourceWithRawResponse, + AsyncAutomationsResourceWithRawResponse, + AutomationsResourceWithStreamingResponse, + AsyncAutomationsResourceWithStreamingResponse, +) +from .environments import ( + EnvironmentsResource, + AsyncEnvironmentsResource, + EnvironmentsResourceWithRawResponse, + AsyncEnvironmentsResourceWithRawResponse, + EnvironmentsResourceWithStreamingResponse, + AsyncEnvironmentsResourceWithStreamingResponse, +) + +__all__ = [ + "AutomationsResource", + "AsyncAutomationsResource", + "AutomationsResourceWithRawResponse", + "AsyncAutomationsResourceWithRawResponse", + "AutomationsResourceWithStreamingResponse", + "AsyncAutomationsResourceWithStreamingResponse", + "ClassesResource", + "AsyncClassesResource", + "ClassesResourceWithRawResponse", + "AsyncClassesResourceWithRawResponse", + "ClassesResourceWithStreamingResponse", + "AsyncClassesResourceWithStreamingResponse", + "EnvironmentsResource", + "AsyncEnvironmentsResource", + "EnvironmentsResourceWithRawResponse", + "AsyncEnvironmentsResourceWithRawResponse", + "EnvironmentsResourceWithStreamingResponse", + "AsyncEnvironmentsResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/environments/automations/__init__.py b/src/gitpod/resources/environments/automations/__init__.py new file mode 100644 index 0000000..a9f609d --- /dev/null +++ b/src/gitpod/resources/environments/automations/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .tasks import ( + TasksResource, + AsyncTasksResource, + TasksResourceWithRawResponse, + AsyncTasksResourceWithRawResponse, + TasksResourceWithStreamingResponse, + AsyncTasksResourceWithStreamingResponse, +) +from .services import ( + ServicesResource, + AsyncServicesResource, + ServicesResourceWithRawResponse, + AsyncServicesResourceWithRawResponse, + ServicesResourceWithStreamingResponse, + AsyncServicesResourceWithStreamingResponse, +) +from .automations import ( + AutomationsResource, + AsyncAutomationsResource, + AutomationsResourceWithRawResponse, + AsyncAutomationsResourceWithRawResponse, + AutomationsResourceWithStreamingResponse, + AsyncAutomationsResourceWithStreamingResponse, +) + +__all__ = [ + "ServicesResource", + "AsyncServicesResource", + "ServicesResourceWithRawResponse", + "AsyncServicesResourceWithRawResponse", + "ServicesResourceWithStreamingResponse", + "AsyncServicesResourceWithStreamingResponse", + "TasksResource", + "AsyncTasksResource", + "TasksResourceWithRawResponse", + "AsyncTasksResourceWithRawResponse", + "TasksResourceWithStreamingResponse", + "AsyncTasksResourceWithStreamingResponse", + "AutomationsResource", + "AsyncAutomationsResource", + "AutomationsResourceWithRawResponse", + "AsyncAutomationsResourceWithRawResponse", + "AutomationsResourceWithStreamingResponse", + "AsyncAutomationsResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/environments/automations/automations.py b/src/gitpod/resources/environments/automations/automations.py new file mode 100644 index 0000000..9eda852 --- /dev/null +++ b/src/gitpod/resources/environments/automations/automations.py @@ -0,0 +1,318 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .services import ( + ServicesResource, + AsyncServicesResource, + ServicesResourceWithRawResponse, + AsyncServicesResourceWithRawResponse, + ServicesResourceWithStreamingResponse, + AsyncServicesResourceWithStreamingResponse, +) +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from .tasks.tasks import ( + TasksResource, + AsyncTasksResource, + TasksResourceWithRawResponse, + AsyncTasksResourceWithRawResponse, + TasksResourceWithStreamingResponse, + AsyncTasksResourceWithStreamingResponse, +) +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.environments import automation_upsert_params +from ....types.environments.automations_file_param import AutomationsFileParam +from ....types.environments.automation_upsert_response import AutomationUpsertResponse + +__all__ = ["AutomationsResource", "AsyncAutomationsResource"] + + +class AutomationsResource(SyncAPIResource): + @cached_property + def services(self) -> ServicesResource: + return ServicesResource(self._client) + + @cached_property + def tasks(self) -> TasksResource: + return TasksResource(self._client) + + @cached_property + def with_raw_response(self) -> AutomationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AutomationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AutomationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AutomationsResourceWithStreamingResponse(self) + + def upsert( + self, + *, + automations_file: AutomationsFileParam | NotGiven = NOT_GIVEN, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> AutomationUpsertResponse: + """ + Upserts the automations file for the given environment. + + Use this method to: + + - Configure environment automations + - Update automation settings + - Manage automation files + + ### Examples + + - Update automations file: + + Updates or creates the automations configuration. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + automationsFile: + services: + web-server: + name: "Web Server" + description: "Development web server" + commands: + start: "npm run dev" + ready: "curl -s http://localhost:3000" + triggeredBy: + - postDevcontainerStart + tasks: + build: + name: "Build Project" + description: "Builds the project artifacts" + command: "npm run build" + triggeredBy: + - postEnvironmentStart + ``` + + Args: + automations_file: WARN: Do not remove any field here, as it will break reading automation yaml + files. We error if there are any unknown fields in the yaml (to ensure the yaml + is correct), but would break if we removed any fields. This includes marking a + field as "reserved" in the proto file, this will also break reading the yaml. + + 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.EnvironmentAutomationService/UpsertAutomationsFile", + body=maybe_transform( + { + "automations_file": automations_file, + "environment_id": environment_id, + }, + automation_upsert_params.AutomationUpsertParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AutomationUpsertResponse, + ) + + +class AsyncAutomationsResource(AsyncAPIResource): + @cached_property + def services(self) -> AsyncServicesResource: + return AsyncServicesResource(self._client) + + @cached_property + def tasks(self) -> AsyncTasksResource: + return AsyncTasksResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncAutomationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncAutomationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAutomationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncAutomationsResourceWithStreamingResponse(self) + + async def upsert( + self, + *, + automations_file: AutomationsFileParam | NotGiven = NOT_GIVEN, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> AutomationUpsertResponse: + """ + Upserts the automations file for the given environment. + + Use this method to: + + - Configure environment automations + - Update automation settings + - Manage automation files + + ### Examples + + - Update automations file: + + Updates or creates the automations configuration. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + automationsFile: + services: + web-server: + name: "Web Server" + description: "Development web server" + commands: + start: "npm run dev" + ready: "curl -s http://localhost:3000" + triggeredBy: + - postDevcontainerStart + tasks: + build: + name: "Build Project" + description: "Builds the project artifacts" + command: "npm run build" + triggeredBy: + - postEnvironmentStart + ``` + + Args: + automations_file: WARN: Do not remove any field here, as it will break reading automation yaml + files. We error if there are any unknown fields in the yaml (to ensure the yaml + is correct), but would break if we removed any fields. This includes marking a + field as "reserved" in the proto file, this will also break reading the yaml. + + 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.EnvironmentAutomationService/UpsertAutomationsFile", + body=await async_maybe_transform( + { + "automations_file": automations_file, + "environment_id": environment_id, + }, + automation_upsert_params.AutomationUpsertParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AutomationUpsertResponse, + ) + + +class AutomationsResourceWithRawResponse: + def __init__(self, automations: AutomationsResource) -> None: + self._automations = automations + + self.upsert = to_raw_response_wrapper( + automations.upsert, + ) + + @cached_property + def services(self) -> ServicesResourceWithRawResponse: + return ServicesResourceWithRawResponse(self._automations.services) + + @cached_property + def tasks(self) -> TasksResourceWithRawResponse: + return TasksResourceWithRawResponse(self._automations.tasks) + + +class AsyncAutomationsResourceWithRawResponse: + def __init__(self, automations: AsyncAutomationsResource) -> None: + self._automations = automations + + self.upsert = async_to_raw_response_wrapper( + automations.upsert, + ) + + @cached_property + def services(self) -> AsyncServicesResourceWithRawResponse: + return AsyncServicesResourceWithRawResponse(self._automations.services) + + @cached_property + def tasks(self) -> AsyncTasksResourceWithRawResponse: + return AsyncTasksResourceWithRawResponse(self._automations.tasks) + + +class AutomationsResourceWithStreamingResponse: + def __init__(self, automations: AutomationsResource) -> None: + self._automations = automations + + self.upsert = to_streamed_response_wrapper( + automations.upsert, + ) + + @cached_property + def services(self) -> ServicesResourceWithStreamingResponse: + return ServicesResourceWithStreamingResponse(self._automations.services) + + @cached_property + def tasks(self) -> TasksResourceWithStreamingResponse: + return TasksResourceWithStreamingResponse(self._automations.tasks) + + +class AsyncAutomationsResourceWithStreamingResponse: + def __init__(self, automations: AsyncAutomationsResource) -> None: + self._automations = automations + + self.upsert = async_to_streamed_response_wrapper( + automations.upsert, + ) + + @cached_property + def services(self) -> AsyncServicesResourceWithStreamingResponse: + return AsyncServicesResourceWithStreamingResponse(self._automations.services) + + @cached_property + def tasks(self) -> AsyncTasksResourceWithStreamingResponse: + return AsyncTasksResourceWithStreamingResponse(self._automations.tasks) diff --git a/src/gitpod/resources/environments/automations/services.py b/src/gitpod/resources/environments/automations/services.py new file mode 100644 index 0000000..0083cfb --- /dev/null +++ b/src/gitpod/resources/environments/automations/services.py @@ -0,0 +1,1136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncServicesPage, AsyncServicesPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.environments.automations import ( + service_list_params, + service_stop_params, + service_start_params, + service_create_params, + service_delete_params, + service_update_params, + service_retrieve_params, +) +from ....types.environments.automations.service import Service +from ....types.environments.automations.service_spec_param import ServiceSpecParam +from ....types.environments.automations.service_metadata_param import ServiceMetadataParam +from ....types.environments.automations.service_create_response import ServiceCreateResponse +from ....types.environments.automations.service_retrieve_response import ServiceRetrieveResponse + +__all__ = ["ServicesResource", "AsyncServicesResource"] + + +class ServicesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ServicesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return ServicesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ServicesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return ServicesResourceWithStreamingResponse(self) + + def create( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + metadata: ServiceMetadataParam | NotGiven = NOT_GIVEN, + spec: ServiceSpecParam | NotGiven = NOT_GIVEN, + # 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, + ) -> ServiceCreateResponse: + """ + Creates a new automation service for an environment. + + Use this method to: + + - Set up long-running services + - Configure service triggers + - Define service dependencies + - Specify runtime environments + + ### Examples + + - Create basic service: + + Creates a simple service with start command. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + metadata: + reference: "web-server" + name: "Web Server" + description: "Runs the development web server" + triggeredBy: + - postDevcontainerStart: true + spec: + commands: + start: "npm run dev" + ready: "curl -s http://localhost:3000" + ``` + + - Create Docker-based service: + + Creates a service running in a specific container. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + metadata: + reference: "redis" + name: "Redis Server" + description: "Redis cache service" + spec: + commands: + start: "redis-server" + runsOn: + docker: + image: "redis:7" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/CreateService", + body=maybe_transform( + { + "environment_id": environment_id, + "metadata": metadata, + "spec": spec, + }, + service_create_params.ServiceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ServiceCreateResponse, + ) + + def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ServiceRetrieveResponse: + """ + Gets details about a specific automation service. + + Use this method to: + + - Check service status + - View service configuration + - Monitor service health + - Retrieve service metadata + + ### Examples + + - Get service details: + + Retrieves information about a specific service. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/GetService", + body=maybe_transform({"id": id}, service_retrieve_params.ServiceRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ServiceRetrieveResponse, + ) + + def update( + self, + *, + id: str | NotGiven = NOT_GIVEN, + metadata: service_update_params.Metadata | NotGiven = NOT_GIVEN, + spec: service_update_params.Spec | NotGiven = NOT_GIVEN, + status: service_update_params.Status | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an automation service configuration. + + Use this method to: + + - Modify service commands + - Update triggers + - Change runtime settings + - Adjust dependencies + + ### Examples + + - Update commands: + + Changes service start and ready commands. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + spec: + commands: + start: "npm run start:dev" + ready: "curl -s http://localhost:8080" + ``` + + - Update triggers: + + Modifies when the service starts. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + metadata: + triggeredBy: + trigger: + - postDevcontainerStart: true + - manual: true + ``` + + Args: + spec: Changing the spec of a service is a complex operation. The spec of a service can + only be updated if the service is in a stopped state. If the service is running, + it must be stopped first. + + status: Service status updates are only expected from the executing environment. As a + client of this API you are not expected to provide this field. Updating this + field requires the `environmentservice:update_status` permission. + + 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.EnvironmentAutomationService/UpdateService", + body=maybe_transform( + { + "id": id, + "metadata": metadata, + "spec": spec, + "status": status, + }, + service_update_params.ServiceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: service_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: service_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncServicesPage[Service]: + """ + Lists automation services with optional filtering. + + Use this method to: + + - View all services in an environment + - Filter services by reference + - Monitor service status + + ### Examples + + - List environment services: + + Shows all services for an environment. + + ```yaml + filter: + environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + pagination: + pageSize: 20 + ``` + + - Filter by reference: + + Lists services matching specific references. + + ```yaml + filter: + references: ["web-server", "database"] + pagination: + pageSize: 20 + ``` + + Args: + filter: filter contains the filter options for listing services + + pagination: pagination contains the pagination options for listing services + + 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._get_api_list( + "/gitpod.v1.EnvironmentAutomationService/ListServices", + page=SyncServicesPage[Service], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + service_list_params.ServiceListParams, + ), + 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, + }, + service_list_params.ServiceListParams, + ), + ), + model=Service, + method="post", + ) + + def delete( + self, + *, + id: str | NotGiven = NOT_GIVEN, + force: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """Deletes an automation service. + + This call does not block until the service is + deleted. If the service is not stopped it will be stopped before deletion. + + Use this method to: + + - Remove unused services + - Clean up service configurations + - Stop and delete services + + ### Examples + + - Delete service: + + Removes a service after stopping it. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + force: false + ``` + + - Force delete: + + Immediately removes a service. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + force: true + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/DeleteService", + body=maybe_transform( + { + "id": id, + "force": force, + }, + service_delete_params.ServiceDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def start( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """Starts an automation service. + + This call does not block until the service is + started. This call will not error if the service is already running or has been + started. + + Use this method to: + + - Start stopped services + - Resume service operations + - Trigger service initialization + + ### Examples + + - Start service: + + Starts a previously stopped service. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/StartService", + body=maybe_transform({"id": id}, service_start_params.ServiceStartParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def stop( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """Stops an automation service. + + This call does not block until the service is + stopped. This call will not error if the service is already stopped or has been + stopped. + + Use this method to: + + - Pause service operations + - Gracefully stop services + - Prepare for updates + + ### Examples + + - Stop service: + + Gracefully stops a running service. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/StopService", + body=maybe_transform({"id": id}, service_stop_params.ServiceStopParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncServicesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncServicesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncServicesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncServicesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncServicesResourceWithStreamingResponse(self) + + async def create( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + metadata: ServiceMetadataParam | NotGiven = NOT_GIVEN, + spec: ServiceSpecParam | NotGiven = NOT_GIVEN, + # 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, + ) -> ServiceCreateResponse: + """ + Creates a new automation service for an environment. + + Use this method to: + + - Set up long-running services + - Configure service triggers + - Define service dependencies + - Specify runtime environments + + ### Examples + + - Create basic service: + + Creates a simple service with start command. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + metadata: + reference: "web-server" + name: "Web Server" + description: "Runs the development web server" + triggeredBy: + - postDevcontainerStart: true + spec: + commands: + start: "npm run dev" + ready: "curl -s http://localhost:3000" + ``` + + - Create Docker-based service: + + Creates a service running in a specific container. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + metadata: + reference: "redis" + name: "Redis Server" + description: "Redis cache service" + spec: + commands: + start: "redis-server" + runsOn: + docker: + image: "redis:7" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/CreateService", + body=await async_maybe_transform( + { + "environment_id": environment_id, + "metadata": metadata, + "spec": spec, + }, + service_create_params.ServiceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ServiceCreateResponse, + ) + + async def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ServiceRetrieveResponse: + """ + Gets details about a specific automation service. + + Use this method to: + + - Check service status + - View service configuration + - Monitor service health + - Retrieve service metadata + + ### Examples + + - Get service details: + + Retrieves information about a specific service. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/GetService", + body=await async_maybe_transform({"id": id}, service_retrieve_params.ServiceRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ServiceRetrieveResponse, + ) + + async def update( + self, + *, + id: str | NotGiven = NOT_GIVEN, + metadata: service_update_params.Metadata | NotGiven = NOT_GIVEN, + spec: service_update_params.Spec | NotGiven = NOT_GIVEN, + status: service_update_params.Status | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an automation service configuration. + + Use this method to: + + - Modify service commands + - Update triggers + - Change runtime settings + - Adjust dependencies + + ### Examples + + - Update commands: + + Changes service start and ready commands. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + spec: + commands: + start: "npm run start:dev" + ready: "curl -s http://localhost:8080" + ``` + + - Update triggers: + + Modifies when the service starts. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + metadata: + triggeredBy: + trigger: + - postDevcontainerStart: true + - manual: true + ``` + + Args: + spec: Changing the spec of a service is a complex operation. The spec of a service can + only be updated if the service is in a stopped state. If the service is running, + it must be stopped first. + + status: Service status updates are only expected from the executing environment. As a + client of this API you are not expected to provide this field. Updating this + field requires the `environmentservice:update_status` permission. + + 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.EnvironmentAutomationService/UpdateService", + body=await async_maybe_transform( + { + "id": id, + "metadata": metadata, + "spec": spec, + "status": status, + }, + service_update_params.ServiceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: service_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: service_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Service, AsyncServicesPage[Service]]: + """ + Lists automation services with optional filtering. + + Use this method to: + + - View all services in an environment + - Filter services by reference + - Monitor service status + + ### Examples + + - List environment services: + + Shows all services for an environment. + + ```yaml + filter: + environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + pagination: + pageSize: 20 + ``` + + - Filter by reference: + + Lists services matching specific references. + + ```yaml + filter: + references: ["web-server", "database"] + pagination: + pageSize: 20 + ``` + + Args: + filter: filter contains the filter options for listing services + + pagination: pagination contains the pagination options for listing services + + 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._get_api_list( + "/gitpod.v1.EnvironmentAutomationService/ListServices", + page=AsyncServicesPage[Service], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + service_list_params.ServiceListParams, + ), + 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, + }, + service_list_params.ServiceListParams, + ), + ), + model=Service, + method="post", + ) + + async def delete( + self, + *, + id: str | NotGiven = NOT_GIVEN, + force: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """Deletes an automation service. + + This call does not block until the service is + deleted. If the service is not stopped it will be stopped before deletion. + + Use this method to: + + - Remove unused services + - Clean up service configurations + - Stop and delete services + + ### Examples + + - Delete service: + + Removes a service after stopping it. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + force: false + ``` + + - Force delete: + + Immediately removes a service. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + force: true + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/DeleteService", + body=await async_maybe_transform( + { + "id": id, + "force": force, + }, + service_delete_params.ServiceDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def start( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """Starts an automation service. + + This call does not block until the service is + started. This call will not error if the service is already running or has been + started. + + Use this method to: + + - Start stopped services + - Resume service operations + - Trigger service initialization + + ### Examples + + - Start service: + + Starts a previously stopped service. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/StartService", + body=await async_maybe_transform({"id": id}, service_start_params.ServiceStartParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def stop( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """Stops an automation service. + + This call does not block until the service is + stopped. This call will not error if the service is already stopped or has been + stopped. + + Use this method to: + + - Pause service operations + - Gracefully stop services + - Prepare for updates + + ### Examples + + - Stop service: + + Gracefully stops a running service. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/StopService", + body=await async_maybe_transform({"id": id}, service_stop_params.ServiceStopParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class ServicesResourceWithRawResponse: + def __init__(self, services: ServicesResource) -> None: + self._services = services + + self.create = to_raw_response_wrapper( + services.create, + ) + self.retrieve = to_raw_response_wrapper( + services.retrieve, + ) + self.update = to_raw_response_wrapper( + services.update, + ) + self.list = to_raw_response_wrapper( + services.list, + ) + self.delete = to_raw_response_wrapper( + services.delete, + ) + self.start = to_raw_response_wrapper( + services.start, + ) + self.stop = to_raw_response_wrapper( + services.stop, + ) + + +class AsyncServicesResourceWithRawResponse: + def __init__(self, services: AsyncServicesResource) -> None: + self._services = services + + self.create = async_to_raw_response_wrapper( + services.create, + ) + self.retrieve = async_to_raw_response_wrapper( + services.retrieve, + ) + self.update = async_to_raw_response_wrapper( + services.update, + ) + self.list = async_to_raw_response_wrapper( + services.list, + ) + self.delete = async_to_raw_response_wrapper( + services.delete, + ) + self.start = async_to_raw_response_wrapper( + services.start, + ) + self.stop = async_to_raw_response_wrapper( + services.stop, + ) + + +class ServicesResourceWithStreamingResponse: + def __init__(self, services: ServicesResource) -> None: + self._services = services + + self.create = to_streamed_response_wrapper( + services.create, + ) + self.retrieve = to_streamed_response_wrapper( + services.retrieve, + ) + self.update = to_streamed_response_wrapper( + services.update, + ) + self.list = to_streamed_response_wrapper( + services.list, + ) + self.delete = to_streamed_response_wrapper( + services.delete, + ) + self.start = to_streamed_response_wrapper( + services.start, + ) + self.stop = to_streamed_response_wrapper( + services.stop, + ) + + +class AsyncServicesResourceWithStreamingResponse: + def __init__(self, services: AsyncServicesResource) -> None: + self._services = services + + self.create = async_to_streamed_response_wrapper( + services.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + services.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + services.update, + ) + self.list = async_to_streamed_response_wrapper( + services.list, + ) + self.delete = async_to_streamed_response_wrapper( + services.delete, + ) + self.start = async_to_streamed_response_wrapper( + services.start, + ) + self.stop = async_to_streamed_response_wrapper( + services.stop, + ) diff --git a/src/gitpod/resources/environments/automations/tasks/__init__.py b/src/gitpod/resources/environments/automations/tasks/__init__.py new file mode 100644 index 0000000..5c1a049 --- /dev/null +++ b/src/gitpod/resources/environments/automations/tasks/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .tasks import ( + TasksResource, + AsyncTasksResource, + TasksResourceWithRawResponse, + AsyncTasksResourceWithRawResponse, + TasksResourceWithStreamingResponse, + AsyncTasksResourceWithStreamingResponse, +) +from .executions import ( + ExecutionsResource, + AsyncExecutionsResource, + ExecutionsResourceWithRawResponse, + AsyncExecutionsResourceWithRawResponse, + ExecutionsResourceWithStreamingResponse, + AsyncExecutionsResourceWithStreamingResponse, +) + +__all__ = [ + "ExecutionsResource", + "AsyncExecutionsResource", + "ExecutionsResourceWithRawResponse", + "AsyncExecutionsResourceWithRawResponse", + "ExecutionsResourceWithStreamingResponse", + "AsyncExecutionsResourceWithStreamingResponse", + "TasksResource", + "AsyncTasksResource", + "TasksResourceWithRawResponse", + "AsyncTasksResourceWithRawResponse", + "TasksResourceWithStreamingResponse", + "AsyncTasksResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/environments/automations/tasks/executions.py b/src/gitpod/resources/environments/automations/tasks/executions.py new file mode 100644 index 0000000..3fff111 --- /dev/null +++ b/src/gitpod/resources/environments/automations/tasks/executions.py @@ -0,0 +1,497 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....pagination import SyncTaskExecutionsPage, AsyncTaskExecutionsPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.shared.task_execution import TaskExecution +from .....types.environments.automations.tasks import ( + execution_list_params, + execution_stop_params, + execution_retrieve_params, +) +from .....types.environments.automations.tasks.execution_retrieve_response import ExecutionRetrieveResponse + +__all__ = ["ExecutionsResource", "AsyncExecutionsResource"] + + +class ExecutionsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ExecutionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return ExecutionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ExecutionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return ExecutionsResourceWithStreamingResponse(self) + + def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ExecutionRetrieveResponse: + """ + Gets details about a specific task execution. + + Use this method to: + + - Monitor execution progress + - View execution logs + - Check execution status + - Debug failed executions + + ### Examples + + - Get execution details: + + Retrieves information about a specific task execution. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/GetTaskExecution", + body=maybe_transform({"id": id}, execution_retrieve_params.ExecutionRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExecutionRetrieveResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: execution_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: execution_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncTaskExecutionsPage[TaskExecution]: + """ + Lists executions of automation tasks. + + Use this method to: + + - View task execution history + - Monitor running tasks + - Track task completion status + + ### Examples + + - List all executions: + + Shows execution history for all tasks. + + ```yaml + filter: + environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + pagination: + pageSize: 20 + ``` + + - Filter by phase: + + Lists executions in specific phases. + + ```yaml + filter: + phases: ["TASK_EXECUTION_PHASE_RUNNING", "TASK_EXECUTION_PHASE_FAILED"] + pagination: + pageSize: 20 + ``` + + Args: + filter: filter contains the filter options for listing task runs + + pagination: pagination contains the pagination options for listing task runs + + 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._get_api_list( + "/gitpod.v1.EnvironmentAutomationService/ListTaskExecutions", + page=SyncTaskExecutionsPage[TaskExecution], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + execution_list_params.ExecutionListParams, + ), + 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, + }, + execution_list_params.ExecutionListParams, + ), + ), + model=TaskExecution, + method="post", + ) + + def stop( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Stops a running task execution. + + Use this method to: + + - Cancel long-running tasks + - Stop failed executions + - Interrupt task processing + + ### Examples + + - Stop execution: + + Stops a running task execution. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/StopTaskExecution", + body=maybe_transform({"id": id}, execution_stop_params.ExecutionStopParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncExecutionsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncExecutionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncExecutionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncExecutionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncExecutionsResourceWithStreamingResponse(self) + + async def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ExecutionRetrieveResponse: + """ + Gets details about a specific task execution. + + Use this method to: + + - Monitor execution progress + - View execution logs + - Check execution status + - Debug failed executions + + ### Examples + + - Get execution details: + + Retrieves information about a specific task execution. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/GetTaskExecution", + body=await async_maybe_transform({"id": id}, execution_retrieve_params.ExecutionRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExecutionRetrieveResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: execution_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: execution_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[TaskExecution, AsyncTaskExecutionsPage[TaskExecution]]: + """ + Lists executions of automation tasks. + + Use this method to: + + - View task execution history + - Monitor running tasks + - Track task completion status + + ### Examples + + - List all executions: + + Shows execution history for all tasks. + + ```yaml + filter: + environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + pagination: + pageSize: 20 + ``` + + - Filter by phase: + + Lists executions in specific phases. + + ```yaml + filter: + phases: ["TASK_EXECUTION_PHASE_RUNNING", "TASK_EXECUTION_PHASE_FAILED"] + pagination: + pageSize: 20 + ``` + + Args: + filter: filter contains the filter options for listing task runs + + pagination: pagination contains the pagination options for listing task runs + + 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._get_api_list( + "/gitpod.v1.EnvironmentAutomationService/ListTaskExecutions", + page=AsyncTaskExecutionsPage[TaskExecution], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + execution_list_params.ExecutionListParams, + ), + 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, + }, + execution_list_params.ExecutionListParams, + ), + ), + model=TaskExecution, + method="post", + ) + + async def stop( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Stops a running task execution. + + Use this method to: + + - Cancel long-running tasks + - Stop failed executions + - Interrupt task processing + + ### Examples + + - Stop execution: + + Stops a running task execution. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/StopTaskExecution", + body=await async_maybe_transform({"id": id}, execution_stop_params.ExecutionStopParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class ExecutionsResourceWithRawResponse: + def __init__(self, executions: ExecutionsResource) -> None: + self._executions = executions + + self.retrieve = to_raw_response_wrapper( + executions.retrieve, + ) + self.list = to_raw_response_wrapper( + executions.list, + ) + self.stop = to_raw_response_wrapper( + executions.stop, + ) + + +class AsyncExecutionsResourceWithRawResponse: + def __init__(self, executions: AsyncExecutionsResource) -> None: + self._executions = executions + + self.retrieve = async_to_raw_response_wrapper( + executions.retrieve, + ) + self.list = async_to_raw_response_wrapper( + executions.list, + ) + self.stop = async_to_raw_response_wrapper( + executions.stop, + ) + + +class ExecutionsResourceWithStreamingResponse: + def __init__(self, executions: ExecutionsResource) -> None: + self._executions = executions + + self.retrieve = to_streamed_response_wrapper( + executions.retrieve, + ) + self.list = to_streamed_response_wrapper( + executions.list, + ) + self.stop = to_streamed_response_wrapper( + executions.stop, + ) + + +class AsyncExecutionsResourceWithStreamingResponse: + def __init__(self, executions: AsyncExecutionsResource) -> None: + self._executions = executions + + self.retrieve = async_to_streamed_response_wrapper( + executions.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + executions.list, + ) + self.stop = async_to_streamed_response_wrapper( + executions.stop, + ) diff --git a/src/gitpod/resources/environments/automations/tasks/tasks.py b/src/gitpod/resources/environments/automations/tasks/tasks.py new file mode 100644 index 0000000..b8a1b22 --- /dev/null +++ b/src/gitpod/resources/environments/automations/tasks/tasks.py @@ -0,0 +1,990 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List + +import httpx + +from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._utils import maybe_transform, async_maybe_transform +from .executions import ( + ExecutionsResource, + AsyncExecutionsResource, + ExecutionsResourceWithRawResponse, + AsyncExecutionsResourceWithRawResponse, + ExecutionsResourceWithStreamingResponse, + AsyncExecutionsResourceWithStreamingResponse, +) +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....pagination import SyncTasksPage, AsyncTasksPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.shared.task import Task +from .....types.shared_params.task_spec import TaskSpec +from .....types.environments.automations import ( + task_list_params, + task_start_params, + task_create_params, + task_delete_params, + task_update_params, + task_retrieve_params, +) +from .....types.shared_params.task_metadata import TaskMetadata +from .....types.environments.automations.task_start_response import TaskStartResponse +from .....types.environments.automations.task_create_response import TaskCreateResponse +from .....types.environments.automations.task_retrieve_response import TaskRetrieveResponse + +__all__ = ["TasksResource", "AsyncTasksResource"] + + +class TasksResource(SyncAPIResource): + @cached_property + def executions(self) -> ExecutionsResource: + return ExecutionsResource(self._client) + + @cached_property + def with_raw_response(self) -> TasksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return TasksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TasksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return TasksResourceWithStreamingResponse(self) + + def create( + self, + *, + depends_on: List[str] | NotGiven = NOT_GIVEN, + environment_id: str | NotGiven = NOT_GIVEN, + metadata: TaskMetadata | NotGiven = NOT_GIVEN, + spec: TaskSpec | NotGiven = NOT_GIVEN, + # 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, + ) -> TaskCreateResponse: + """ + Creates a new automation task. + + Use this method to: + + - Define one-off or scheduled tasks + - Set up build or test automation + - Configure task dependencies + - Specify execution environments + + ### Examples + + - Create basic task: + + Creates a simple build task. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + metadata: + reference: "build" + name: "Build Project" + description: "Builds the project artifacts" + triggeredBy: + - postEnvironmentStart: true + spec: + command: "npm run build" + ``` + + - Create task with dependencies: + + Creates a task that depends on other services. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + metadata: + reference: "test" + name: "Run Tests" + description: "Runs the test suite" + spec: + command: "npm test" + dependsOn: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/CreateTask", + body=maybe_transform( + { + "depends_on": depends_on, + "environment_id": environment_id, + "metadata": metadata, + "spec": spec, + }, + task_create_params.TaskCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskCreateResponse, + ) + + def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> TaskRetrieveResponse: + """ + Gets details about a specific automation task. + + Use this method to: + + - Check task configuration + - View task dependencies + - Monitor task status + + ### Examples + + - Get task details: + + Retrieves information about a specific task. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/GetTask", + body=maybe_transform({"id": id}, task_retrieve_params.TaskRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskRetrieveResponse, + ) + + def update( + self, + *, + id: str | NotGiven = NOT_GIVEN, + depends_on: List[str] | NotGiven = NOT_GIVEN, + metadata: task_update_params.Metadata | NotGiven = NOT_GIVEN, + spec: task_update_params.Spec | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an automation task configuration. + + Use this method to: + + - Modify task commands + - Update task triggers + - Change dependencies + - Adjust execution settings + + ### Examples + + - Update command: + + Changes the task's command. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + spec: + command: "npm run test:coverage" + ``` + + - Update triggers: + + Modifies when the task runs. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + metadata: + triggeredBy: + trigger: + - postEnvironmentStart: true + ``` + + Args: + depends_on: dependencies specifies the IDs of the automations this task depends on. + + 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.EnvironmentAutomationService/UpdateTask", + body=maybe_transform( + { + "id": id, + "depends_on": depends_on, + "metadata": metadata, + "spec": spec, + }, + task_update_params.TaskUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: task_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: task_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncTasksPage[Task]: + """ + Lists automation tasks with optional filtering. + + Use this method to: + + - View all tasks in an environment + - Filter tasks by reference + - Monitor task status + + ### Examples + + - List environment tasks: + + Shows all tasks for an environment. + + ```yaml + filter: + environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + pagination: + pageSize: 20 + ``` + + - Filter by reference: + + Lists tasks matching specific references. + + ```yaml + filter: + references: ["build", "test"] + pagination: + pageSize: 20 + ``` + + Args: + filter: filter contains the filter options for listing tasks + + pagination: pagination contains the pagination options for listing tasks + + 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._get_api_list( + "/gitpod.v1.EnvironmentAutomationService/ListTasks", + page=SyncTasksPage[Task], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + task_list_params.TaskListParams, + ), + 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, + }, + task_list_params.TaskListParams, + ), + ), + model=Task, + method="post", + ) + + def delete( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes an automation task. + + Use this method to: + + - Remove unused tasks + - Clean up task configurations + - Delete obsolete automations + + ### Examples + + - Delete task: + + Removes a task and its configuration. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/DeleteTask", + body=maybe_transform({"id": id}, task_delete_params.TaskDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def start( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> TaskStartResponse: + """Starts a task by creating a new task execution. + + This call does not block until + the task is started; the task will be started asynchronously. + + Use this method to: + + - Trigger task execution + - Run one-off tasks + - Start scheduled tasks immediately + + ### Examples + + - Start task: + + Creates a new execution of a task. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.EnvironmentAutomationService/StartTask", + body=maybe_transform({"id": id}, task_start_params.TaskStartParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskStartResponse, + ) + + +class AsyncTasksResource(AsyncAPIResource): + @cached_property + def executions(self) -> AsyncExecutionsResource: + return AsyncExecutionsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncTasksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncTasksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTasksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncTasksResourceWithStreamingResponse(self) + + async def create( + self, + *, + depends_on: List[str] | NotGiven = NOT_GIVEN, + environment_id: str | NotGiven = NOT_GIVEN, + metadata: TaskMetadata | NotGiven = NOT_GIVEN, + spec: TaskSpec | NotGiven = NOT_GIVEN, + # 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, + ) -> TaskCreateResponse: + """ + Creates a new automation task. + + Use this method to: + + - Define one-off or scheduled tasks + - Set up build or test automation + - Configure task dependencies + - Specify execution environments + + ### Examples + + - Create basic task: + + Creates a simple build task. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + metadata: + reference: "build" + name: "Build Project" + description: "Builds the project artifacts" + triggeredBy: + - postEnvironmentStart: true + spec: + command: "npm run build" + ``` + + - Create task with dependencies: + + Creates a task that depends on other services. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + metadata: + reference: "test" + name: "Run Tests" + description: "Runs the test suite" + spec: + command: "npm test" + dependsOn: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/CreateTask", + body=await async_maybe_transform( + { + "depends_on": depends_on, + "environment_id": environment_id, + "metadata": metadata, + "spec": spec, + }, + task_create_params.TaskCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskCreateResponse, + ) + + async def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> TaskRetrieveResponse: + """ + Gets details about a specific automation task. + + Use this method to: + + - Check task configuration + - View task dependencies + - Monitor task status + + ### Examples + + - Get task details: + + Retrieves information about a specific task. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/GetTask", + body=await async_maybe_transform({"id": id}, task_retrieve_params.TaskRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskRetrieveResponse, + ) + + async def update( + self, + *, + id: str | NotGiven = NOT_GIVEN, + depends_on: List[str] | NotGiven = NOT_GIVEN, + metadata: task_update_params.Metadata | NotGiven = NOT_GIVEN, + spec: task_update_params.Spec | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an automation task configuration. + + Use this method to: + + - Modify task commands + - Update task triggers + - Change dependencies + - Adjust execution settings + + ### Examples + + - Update command: + + Changes the task's command. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + spec: + command: "npm run test:coverage" + ``` + + - Update triggers: + + Modifies when the task runs. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + metadata: + triggeredBy: + trigger: + - postEnvironmentStart: true + ``` + + Args: + depends_on: dependencies specifies the IDs of the automations this task depends on. + + 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.EnvironmentAutomationService/UpdateTask", + body=await async_maybe_transform( + { + "id": id, + "depends_on": depends_on, + "metadata": metadata, + "spec": spec, + }, + task_update_params.TaskUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: task_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: task_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Task, AsyncTasksPage[Task]]: + """ + Lists automation tasks with optional filtering. + + Use this method to: + + - View all tasks in an environment + - Filter tasks by reference + - Monitor task status + + ### Examples + + - List environment tasks: + + Shows all tasks for an environment. + + ```yaml + filter: + environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + pagination: + pageSize: 20 + ``` + + - Filter by reference: + + Lists tasks matching specific references. + + ```yaml + filter: + references: ["build", "test"] + pagination: + pageSize: 20 + ``` + + Args: + filter: filter contains the filter options for listing tasks + + pagination: pagination contains the pagination options for listing tasks + + 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._get_api_list( + "/gitpod.v1.EnvironmentAutomationService/ListTasks", + page=AsyncTasksPage[Task], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + task_list_params.TaskListParams, + ), + 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, + }, + task_list_params.TaskListParams, + ), + ), + model=Task, + method="post", + ) + + async def delete( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes an automation task. + + Use this method to: + + - Remove unused tasks + - Clean up task configurations + - Delete obsolete automations + + ### Examples + + - Delete task: + + Removes a task and its configuration. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/DeleteTask", + body=await async_maybe_transform({"id": id}, task_delete_params.TaskDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def start( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> TaskStartResponse: + """Starts a task by creating a new task execution. + + This call does not block until + the task is started; the task will be started asynchronously. + + Use this method to: + + - Trigger task execution + - Run one-off tasks + - Start scheduled tasks immediately + + ### Examples + + - Start task: + + Creates a new execution of a task. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.EnvironmentAutomationService/StartTask", + body=await async_maybe_transform({"id": id}, task_start_params.TaskStartParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskStartResponse, + ) + + +class TasksResourceWithRawResponse: + def __init__(self, tasks: TasksResource) -> None: + self._tasks = tasks + + self.create = to_raw_response_wrapper( + tasks.create, + ) + self.retrieve = to_raw_response_wrapper( + tasks.retrieve, + ) + self.update = to_raw_response_wrapper( + tasks.update, + ) + self.list = to_raw_response_wrapper( + tasks.list, + ) + self.delete = to_raw_response_wrapper( + tasks.delete, + ) + self.start = to_raw_response_wrapper( + tasks.start, + ) + + @cached_property + def executions(self) -> ExecutionsResourceWithRawResponse: + return ExecutionsResourceWithRawResponse(self._tasks.executions) + + +class AsyncTasksResourceWithRawResponse: + def __init__(self, tasks: AsyncTasksResource) -> None: + self._tasks = tasks + + self.create = async_to_raw_response_wrapper( + tasks.create, + ) + self.retrieve = async_to_raw_response_wrapper( + tasks.retrieve, + ) + self.update = async_to_raw_response_wrapper( + tasks.update, + ) + self.list = async_to_raw_response_wrapper( + tasks.list, + ) + self.delete = async_to_raw_response_wrapper( + tasks.delete, + ) + self.start = async_to_raw_response_wrapper( + tasks.start, + ) + + @cached_property + def executions(self) -> AsyncExecutionsResourceWithRawResponse: + return AsyncExecutionsResourceWithRawResponse(self._tasks.executions) + + +class TasksResourceWithStreamingResponse: + def __init__(self, tasks: TasksResource) -> None: + self._tasks = tasks + + self.create = to_streamed_response_wrapper( + tasks.create, + ) + self.retrieve = to_streamed_response_wrapper( + tasks.retrieve, + ) + self.update = to_streamed_response_wrapper( + tasks.update, + ) + self.list = to_streamed_response_wrapper( + tasks.list, + ) + self.delete = to_streamed_response_wrapper( + tasks.delete, + ) + self.start = to_streamed_response_wrapper( + tasks.start, + ) + + @cached_property + def executions(self) -> ExecutionsResourceWithStreamingResponse: + return ExecutionsResourceWithStreamingResponse(self._tasks.executions) + + +class AsyncTasksResourceWithStreamingResponse: + def __init__(self, tasks: AsyncTasksResource) -> None: + self._tasks = tasks + + self.create = async_to_streamed_response_wrapper( + tasks.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + tasks.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + tasks.update, + ) + self.list = async_to_streamed_response_wrapper( + tasks.list, + ) + self.delete = async_to_streamed_response_wrapper( + tasks.delete, + ) + self.start = async_to_streamed_response_wrapper( + tasks.start, + ) + + @cached_property + def executions(self) -> AsyncExecutionsResourceWithStreamingResponse: + return AsyncExecutionsResourceWithStreamingResponse(self._tasks.executions) diff --git a/src/gitpod/resources/environments/classes.py b/src/gitpod/resources/environments/classes.py new file mode 100644 index 0000000..ffe58db --- /dev/null +++ b/src/gitpod/resources/environments/classes.py @@ -0,0 +1,244 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncEnvironmentClassesPage, AsyncEnvironmentClassesPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.environments import class_list_params +from ...types.shared.environment_class import EnvironmentClass + +__all__ = ["ClassesResource", "AsyncClassesResource"] + + +class ClassesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ClassesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return ClassesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ClassesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return ClassesResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: class_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: class_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncEnvironmentClassesPage[EnvironmentClass]: + """ + Lists available environment classes with their specifications and resource + limits. + + Use this method to understand what types of environments you can create and + their capabilities. Environment classes define the compute resources and + features available to your environments. + + ### Examples + + - List all available classes: + + Retrieves a list of all environment classes with their specifications. + + ```yaml + {} + ``` + + buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + + Args: + pagination: pagination contains the pagination options for listing environment classes + + 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._get_api_list( + "/gitpod.v1.EnvironmentService/ListEnvironmentClasses", + page=SyncEnvironmentClassesPage[EnvironmentClass], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + class_list_params.ClassListParams, + ), + 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, + }, + class_list_params.ClassListParams, + ), + ), + model=EnvironmentClass, + method="post", + ) + + +class AsyncClassesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncClassesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncClassesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncClassesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncClassesResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: class_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: class_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[EnvironmentClass, AsyncEnvironmentClassesPage[EnvironmentClass]]: + """ + Lists available environment classes with their specifications and resource + limits. + + Use this method to understand what types of environments you can create and + their capabilities. Environment classes define the compute resources and + features available to your environments. + + ### Examples + + - List all available classes: + + Retrieves a list of all environment classes with their specifications. + + ```yaml + {} + ``` + + buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + + Args: + pagination: pagination contains the pagination options for listing environment classes + + 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._get_api_list( + "/gitpod.v1.EnvironmentService/ListEnvironmentClasses", + page=AsyncEnvironmentClassesPage[EnvironmentClass], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + class_list_params.ClassListParams, + ), + 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, + }, + class_list_params.ClassListParams, + ), + ), + model=EnvironmentClass, + method="post", + ) + + +class ClassesResourceWithRawResponse: + def __init__(self, classes: ClassesResource) -> None: + self._classes = classes + + self.list = to_raw_response_wrapper( + classes.list, + ) + + +class AsyncClassesResourceWithRawResponse: + def __init__(self, classes: AsyncClassesResource) -> None: + self._classes = classes + + self.list = async_to_raw_response_wrapper( + classes.list, + ) + + +class ClassesResourceWithStreamingResponse: + def __init__(self, classes: ClassesResource) -> None: + self._classes = classes + + self.list = to_streamed_response_wrapper( + classes.list, + ) + + +class AsyncClassesResourceWithStreamingResponse: + def __init__(self, classes: AsyncClassesResource) -> None: + self._classes = classes + + self.list = async_to_streamed_response_wrapper( + classes.list, + ) diff --git a/src/gitpod/resources/environments/environments.py b/src/gitpod/resources/environments/environments.py new file mode 100644 index 0000000..e57316b --- /dev/null +++ b/src/gitpod/resources/environments/environments.py @@ -0,0 +1,1892 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ...types import ( + environment_list_params, + environment_stop_params, + environment_start_params, + environment_create_params, + environment_delete_params, + environment_update_params, + environment_retrieve_params, + environment_unarchive_params, + environment_mark_active_params, + environment_create_logs_token_params, + environment_create_from_project_params, + environment_create_environment_token_params, +) +from .classes import ( + ClassesResource, + AsyncClassesResource, + ClassesResourceWithRawResponse, + AsyncClassesResourceWithRawResponse, + ClassesResourceWithStreamingResponse, + AsyncClassesResourceWithStreamingResponse, +) +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncEnvironmentsPage, AsyncEnvironmentsPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.environment import Environment +from .automations.automations import ( + AutomationsResource, + AsyncAutomationsResource, + AutomationsResourceWithRawResponse, + AsyncAutomationsResourceWithRawResponse, + AutomationsResourceWithStreamingResponse, + AsyncAutomationsResourceWithStreamingResponse, +) +from ...types.environment_spec_param import EnvironmentSpecParam +from ...types.environment_create_response import EnvironmentCreateResponse +from ...types.environment_retrieve_response import EnvironmentRetrieveResponse +from ...types.environment_activity_signal_param import EnvironmentActivitySignalParam +from ...types.environment_create_logs_token_response import EnvironmentCreateLogsTokenResponse +from ...types.environment_create_from_project_response import EnvironmentCreateFromProjectResponse +from ...types.environment_create_environment_token_response import EnvironmentCreateEnvironmentTokenResponse + +__all__ = ["EnvironmentsResource", "AsyncEnvironmentsResource"] + + +class EnvironmentsResource(SyncAPIResource): + @cached_property + def automations(self) -> AutomationsResource: + return AutomationsResource(self._client) + + @cached_property + def classes(self) -> ClassesResource: + return ClassesResource(self._client) + + @cached_property + def with_raw_response(self) -> EnvironmentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return EnvironmentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> EnvironmentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return EnvironmentsResourceWithStreamingResponse(self) + + def create( + self, + *, + spec: EnvironmentSpecParam | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentCreateResponse: + """Creates a development environment from a context URL (e.g. + + Git repository) and + starts it. + + The `class` field must be a valid environment class ID. You can find a list of + available environment classes with the `ListEnvironmentClasses` method. + + ### Examples + + - Create from context URL: + + Creates an environment from a Git repository URL with default settings. + + ```yaml + spec: + machine: + class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + content: + initializer: + specs: + - contextUrl: + url: "https://github.com/gitpod-io/gitpod" + ``` + + - Create from Git repository: + + Creates an environment from a Git repository with specific branch targeting. + + ```yaml + spec: + machine: + class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + content: + initializer: + specs: + - git: + remoteUri: "https://github.com/gitpod-io/gitpod" + cloneTarget: "main" + targetMode: "CLONE_TARGET_MODE_REMOTE_BRANCH" + ``` + + - Create with custom timeout and ports: + + Creates an environment with custom inactivity timeout and exposed port + configuration. + + ```yaml + spec: + machine: + class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + content: + initializer: + specs: + - contextUrl: + url: "https://github.com/gitpod-io/gitpod" + timeout: + disconnected: "7200s" # 2 hours in seconds + ports: + - port: 3000 + admission: "ADMISSION_LEVEL_EVERYONE" + name: "Web App" + ``` + + Args: + spec: spec is the configuration of the environment that's required for the to start + the environment + + 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.EnvironmentService/CreateEnvironment", + body=maybe_transform({"spec": spec}, environment_create_params.EnvironmentCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentCreateResponse, + ) + + def retrieve( + self, + *, + environment_id: str, + # 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, + ) -> EnvironmentRetrieveResponse: + """ + Gets details about a specific environment including its status, configuration, + and context URL. + + Use this method to: + + - Check if an environment is ready to use + - Get connection details for IDE and exposed ports + - Monitor environment health and resource usage + - Debug environment setup issues + + ### Examples + + - Get environment details: + + Retrieves detailed information about a specific environment using its unique + identifier. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment to get + + 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.EnvironmentService/GetEnvironment", + body=maybe_transform( + {"environment_id": environment_id}, environment_retrieve_params.EnvironmentRetrieveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentRetrieveResponse, + ) + + def update( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + metadata: Optional[environment_update_params.Metadata] | NotGiven = NOT_GIVEN, + spec: Optional[environment_update_params.Spec] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an environment's configuration while it is running. + + Updates are limited to: + + - Git credentials (username, email) + - SSH public keys + - Content initialization + - Port configurations + - Automation files + - Environment timeouts + + ### Examples + + - Update Git credentials: + + Updates the Git configuration for the environment. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + spec: + content: + gitUsername: "example-user" + gitEmail: "user@example.com" + ``` + + - Add SSH public key: + + Adds a new SSH public key for authentication. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + spec: + sshPublicKeys: + - id: "0194b7c1-c954-718d-91a4-9a742aa5fc11" + value: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + ``` + + - Update content session: + + Updates the content session identifier for the environment. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + spec: + content: + session: "0194b7c1-c954-718d-91a4-9a742aa5fc11" + ``` + + Note: Machine class changes require stopping the environment and creating a new + one. + + Args: + environment_id: environment_id specifies which environment should be updated. + + +required + + 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.EnvironmentService/UpdateEnvironment", + body=maybe_transform( + { + "environment_id": environment_id, + "metadata": metadata, + "spec": spec, + }, + environment_update_params.EnvironmentUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: environment_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: environment_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncEnvironmentsPage[Environment]: + """ + Lists all environments matching the specified criteria. + + Use this method to find and monitor environments across your organization. + Results are ordered by creation time with newest environments first. + + ### Examples + + - List running environments for a project: + + Retrieves all running environments for a specific project with pagination. + + ```yaml + filter: + statusPhases: ["ENVIRONMENT_PHASE_RUNNING"] + projectIds: ["b0e12f6c-4c67-429d-a4a6-d9838b5da047"] + pagination: + pageSize: 10 + ``` + + - List all environments for a specific runner: + + Filters environments by runner ID and creator ID. + + ```yaml + filter: + runnerIds: ["e6aa9c54-89d3-42c1-ac31-bd8d8f1concentrate"] + creatorIds: ["f53d2330-3795-4c5d-a1f3-453121af9c60"] + ``` + + - List stopped and deleted environments: + + Retrieves all environments in stopped or deleted state. + + ```yaml + filter: + statusPhases: ["ENVIRONMENT_PHASE_STOPPED", "ENVIRONMENT_PHASE_DELETED"] + ``` + + Args: + pagination: pagination contains the pagination options for listing environments + + 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._get_api_list( + "/gitpod.v1.EnvironmentService/ListEnvironments", + page=SyncEnvironmentsPage[Environment], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + environment_list_params.EnvironmentListParams, + ), + 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, + }, + environment_list_params.EnvironmentListParams, + ), + ), + model=Environment, + method="post", + ) + + def delete( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + force: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Permanently deletes an environment. + + Running environments are automatically stopped before deletion. If force is + true, the environment is deleted immediately without graceful shutdown. + + ### Examples + + - Delete with graceful shutdown: + + Deletes an environment after gracefully stopping it. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + force: false + ``` + + - Force delete: + + Immediately deletes an environment without waiting for graceful shutdown. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + force: true + ``` + + Args: + environment_id: environment_id specifies the environment that is going to delete. + + +required + + force: force indicates whether the environment should be deleted forcefully When force + deleting an Environment, the Environment is removed immediately and environment + lifecycle is not respected. Force deleting can result in data loss on the + environment. + + 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.EnvironmentService/DeleteEnvironment", + body=maybe_transform( + { + "environment_id": environment_id, + "force": force, + }, + environment_delete_params.EnvironmentDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def create_environment_token( + self, + *, + environment_id: str, + # 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, + ) -> EnvironmentCreateEnvironmentTokenResponse: + """ + Creates an access token for the environment. + + Generated tokens are valid for one hour and provide environment-specific access + permissions. The token is scoped to a specific environment. + + ### Examples + + - Generate environment token: + + Creates a temporary access token for accessing an environment. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment for which the access token should be + created. + + 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.EnvironmentService/CreateEnvironmentAccessToken", + body=maybe_transform( + {"environment_id": environment_id}, + environment_create_environment_token_params.EnvironmentCreateEnvironmentTokenParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentCreateEnvironmentTokenResponse, + ) + + def create_from_project( + self, + *, + project_id: str | NotGiven = NOT_GIVEN, + spec: EnvironmentSpecParam | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentCreateFromProjectResponse: + """ + Creates an environment from an existing project configuration and starts it. + + This method uses project settings as defaults but allows overriding specific + configurations. Project settings take precedence over default configurations, + while custom specifications in the request override project settings. + + ### Examples + + - Create with project defaults: + + Creates an environment using all default settings from the project + configuration. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + - Create with custom compute resources: + + Creates an environment from project with custom machine class and timeout + settings. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + spec: + machine: + class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + timeout: + disconnected: "14400s" # 4 hours in seconds + ``` + + Args: + spec: Spec is the configuration of the environment that's required for the runner to + start the environment Configuration already defined in the Project will override + parts of the spec, if set + + 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.EnvironmentService/CreateEnvironmentFromProject", + body=maybe_transform( + { + "project_id": project_id, + "spec": spec, + }, + environment_create_from_project_params.EnvironmentCreateFromProjectParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentCreateFromProjectResponse, + ) + + def create_logs_token( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentCreateLogsTokenResponse: + """ + Creates an access token for retrieving environment logs. + + Generated tokens are valid for one hour and provide read-only access to the + environment's logs. + + ### Examples + + - Generate logs token: + + Creates a temporary access token for retrieving environment logs. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment for which the logs token should be + created. + + +required + + 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.EnvironmentService/CreateEnvironmentLogsToken", + body=maybe_transform( + {"environment_id": environment_id}, + environment_create_logs_token_params.EnvironmentCreateLogsTokenParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentCreateLogsTokenResponse, + ) + + def mark_active( + self, + *, + activity_signal: EnvironmentActivitySignalParam | NotGiven = NOT_GIVEN, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Records environment activity to prevent automatic shutdown. + + Activity signals should be sent every 5 minutes while the environment is + actively being used. The source must be between 3-80 characters. + + ### Examples + + - Signal VS Code activity: + + Records VS Code editor activity to prevent environment shutdown. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + activitySignal: + source: "VS Code" + timestamp: "2025-02-12T14:30:00Z" + ``` + + Args: + activity_signal: activity_signal specifies the activity. + + environment_id: The ID of the environment to update activity 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.EnvironmentService/MarkEnvironmentActive", + body=maybe_transform( + { + "activity_signal": activity_signal, + "environment_id": environment_id, + }, + environment_mark_active_params.EnvironmentMarkActiveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def start( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Starts a stopped environment. + + Use this method to resume work on a previously stopped environment. The + environment retains its configuration and workspace content from when it was + stopped. + + ### Examples + + - Start an environment: + + Resumes a previously stopped environment with its existing configuration. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies which environment should be started. + + 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.EnvironmentService/StartEnvironment", + body=maybe_transform({"environment_id": environment_id}, environment_start_params.EnvironmentStartParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def stop( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Stops a running environment. + + Use this method to pause work while preserving the environment's state. The + environment can be resumed later using StartEnvironment. + + ### Examples + + - Stop an environment: + + Gracefully stops a running environment while preserving its state. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies which environment should be stopped. + + +required + + 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.EnvironmentService/StopEnvironment", + body=maybe_transform({"environment_id": environment_id}, environment_stop_params.EnvironmentStopParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def unarchive( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Unarchives an environment. + + ### Examples + + - Unarchive an environment: + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment to unarchive. + + +required + + 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.EnvironmentService/UnarchiveEnvironment", + body=maybe_transform( + {"environment_id": environment_id}, environment_unarchive_params.EnvironmentUnarchiveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncEnvironmentsResource(AsyncAPIResource): + @cached_property + def automations(self) -> AsyncAutomationsResource: + return AsyncAutomationsResource(self._client) + + @cached_property + def classes(self) -> AsyncClassesResource: + return AsyncClassesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncEnvironmentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncEnvironmentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncEnvironmentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncEnvironmentsResourceWithStreamingResponse(self) + + async def create( + self, + *, + spec: EnvironmentSpecParam | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentCreateResponse: + """Creates a development environment from a context URL (e.g. + + Git repository) and + starts it. + + The `class` field must be a valid environment class ID. You can find a list of + available environment classes with the `ListEnvironmentClasses` method. + + ### Examples + + - Create from context URL: + + Creates an environment from a Git repository URL with default settings. + + ```yaml + spec: + machine: + class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + content: + initializer: + specs: + - contextUrl: + url: "https://github.com/gitpod-io/gitpod" + ``` + + - Create from Git repository: + + Creates an environment from a Git repository with specific branch targeting. + + ```yaml + spec: + machine: + class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + content: + initializer: + specs: + - git: + remoteUri: "https://github.com/gitpod-io/gitpod" + cloneTarget: "main" + targetMode: "CLONE_TARGET_MODE_REMOTE_BRANCH" + ``` + + - Create with custom timeout and ports: + + Creates an environment with custom inactivity timeout and exposed port + configuration. + + ```yaml + spec: + machine: + class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + content: + initializer: + specs: + - contextUrl: + url: "https://github.com/gitpod-io/gitpod" + timeout: + disconnected: "7200s" # 2 hours in seconds + ports: + - port: 3000 + admission: "ADMISSION_LEVEL_EVERYONE" + name: "Web App" + ``` + + Args: + spec: spec is the configuration of the environment that's required for the to start + the environment + + 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.EnvironmentService/CreateEnvironment", + body=await async_maybe_transform({"spec": spec}, environment_create_params.EnvironmentCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentCreateResponse, + ) + + async def retrieve( + self, + *, + environment_id: str, + # 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, + ) -> EnvironmentRetrieveResponse: + """ + Gets details about a specific environment including its status, configuration, + and context URL. + + Use this method to: + + - Check if an environment is ready to use + - Get connection details for IDE and exposed ports + - Monitor environment health and resource usage + - Debug environment setup issues + + ### Examples + + - Get environment details: + + Retrieves detailed information about a specific environment using its unique + identifier. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment to get + + 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.EnvironmentService/GetEnvironment", + body=await async_maybe_transform( + {"environment_id": environment_id}, environment_retrieve_params.EnvironmentRetrieveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentRetrieveResponse, + ) + + async def update( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + metadata: Optional[environment_update_params.Metadata] | NotGiven = NOT_GIVEN, + spec: Optional[environment_update_params.Spec] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an environment's configuration while it is running. + + Updates are limited to: + + - Git credentials (username, email) + - SSH public keys + - Content initialization + - Port configurations + - Automation files + - Environment timeouts + + ### Examples + + - Update Git credentials: + + Updates the Git configuration for the environment. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + spec: + content: + gitUsername: "example-user" + gitEmail: "user@example.com" + ``` + + - Add SSH public key: + + Adds a new SSH public key for authentication. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + spec: + sshPublicKeys: + - id: "0194b7c1-c954-718d-91a4-9a742aa5fc11" + value: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + ``` + + - Update content session: + + Updates the content session identifier for the environment. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + spec: + content: + session: "0194b7c1-c954-718d-91a4-9a742aa5fc11" + ``` + + Note: Machine class changes require stopping the environment and creating a new + one. + + Args: + environment_id: environment_id specifies which environment should be updated. + + +required + + 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.EnvironmentService/UpdateEnvironment", + body=await async_maybe_transform( + { + "environment_id": environment_id, + "metadata": metadata, + "spec": spec, + }, + environment_update_params.EnvironmentUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: environment_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: environment_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Environment, AsyncEnvironmentsPage[Environment]]: + """ + Lists all environments matching the specified criteria. + + Use this method to find and monitor environments across your organization. + Results are ordered by creation time with newest environments first. + + ### Examples + + - List running environments for a project: + + Retrieves all running environments for a specific project with pagination. + + ```yaml + filter: + statusPhases: ["ENVIRONMENT_PHASE_RUNNING"] + projectIds: ["b0e12f6c-4c67-429d-a4a6-d9838b5da047"] + pagination: + pageSize: 10 + ``` + + - List all environments for a specific runner: + + Filters environments by runner ID and creator ID. + + ```yaml + filter: + runnerIds: ["e6aa9c54-89d3-42c1-ac31-bd8d8f1concentrate"] + creatorIds: ["f53d2330-3795-4c5d-a1f3-453121af9c60"] + ``` + + - List stopped and deleted environments: + + Retrieves all environments in stopped or deleted state. + + ```yaml + filter: + statusPhases: ["ENVIRONMENT_PHASE_STOPPED", "ENVIRONMENT_PHASE_DELETED"] + ``` + + Args: + pagination: pagination contains the pagination options for listing environments + + 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._get_api_list( + "/gitpod.v1.EnvironmentService/ListEnvironments", + page=AsyncEnvironmentsPage[Environment], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + environment_list_params.EnvironmentListParams, + ), + 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, + }, + environment_list_params.EnvironmentListParams, + ), + ), + model=Environment, + method="post", + ) + + async def delete( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + force: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Permanently deletes an environment. + + Running environments are automatically stopped before deletion. If force is + true, the environment is deleted immediately without graceful shutdown. + + ### Examples + + - Delete with graceful shutdown: + + Deletes an environment after gracefully stopping it. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + force: false + ``` + + - Force delete: + + Immediately deletes an environment without waiting for graceful shutdown. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + force: true + ``` + + Args: + environment_id: environment_id specifies the environment that is going to delete. + + +required + + force: force indicates whether the environment should be deleted forcefully When force + deleting an Environment, the Environment is removed immediately and environment + lifecycle is not respected. Force deleting can result in data loss on the + environment. + + 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.EnvironmentService/DeleteEnvironment", + body=await async_maybe_transform( + { + "environment_id": environment_id, + "force": force, + }, + environment_delete_params.EnvironmentDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def create_environment_token( + self, + *, + environment_id: str, + # 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, + ) -> EnvironmentCreateEnvironmentTokenResponse: + """ + Creates an access token for the environment. + + Generated tokens are valid for one hour and provide environment-specific access + permissions. The token is scoped to a specific environment. + + ### Examples + + - Generate environment token: + + Creates a temporary access token for accessing an environment. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment for which the access token should be + created. + + 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.EnvironmentService/CreateEnvironmentAccessToken", + body=await async_maybe_transform( + {"environment_id": environment_id}, + environment_create_environment_token_params.EnvironmentCreateEnvironmentTokenParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentCreateEnvironmentTokenResponse, + ) + + async def create_from_project( + self, + *, + project_id: str | NotGiven = NOT_GIVEN, + spec: EnvironmentSpecParam | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentCreateFromProjectResponse: + """ + Creates an environment from an existing project configuration and starts it. + + This method uses project settings as defaults but allows overriding specific + configurations. Project settings take precedence over default configurations, + while custom specifications in the request override project settings. + + ### Examples + + - Create with project defaults: + + Creates an environment using all default settings from the project + configuration. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + - Create with custom compute resources: + + Creates an environment from project with custom machine class and timeout + settings. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + spec: + machine: + class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + timeout: + disconnected: "14400s" # 4 hours in seconds + ``` + + Args: + spec: Spec is the configuration of the environment that's required for the runner to + start the environment Configuration already defined in the Project will override + parts of the spec, if set + + 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.EnvironmentService/CreateEnvironmentFromProject", + body=await async_maybe_transform( + { + "project_id": project_id, + "spec": spec, + }, + environment_create_from_project_params.EnvironmentCreateFromProjectParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentCreateFromProjectResponse, + ) + + async def create_logs_token( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentCreateLogsTokenResponse: + """ + Creates an access token for retrieving environment logs. + + Generated tokens are valid for one hour and provide read-only access to the + environment's logs. + + ### Examples + + - Generate logs token: + + Creates a temporary access token for retrieving environment logs. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment for which the logs token should be + created. + + +required + + 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.EnvironmentService/CreateEnvironmentLogsToken", + body=await async_maybe_transform( + {"environment_id": environment_id}, + environment_create_logs_token_params.EnvironmentCreateLogsTokenParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentCreateLogsTokenResponse, + ) + + async def mark_active( + self, + *, + activity_signal: EnvironmentActivitySignalParam | NotGiven = NOT_GIVEN, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Records environment activity to prevent automatic shutdown. + + Activity signals should be sent every 5 minutes while the environment is + actively being used. The source must be between 3-80 characters. + + ### Examples + + - Signal VS Code activity: + + Records VS Code editor activity to prevent environment shutdown. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + activitySignal: + source: "VS Code" + timestamp: "2025-02-12T14:30:00Z" + ``` + + Args: + activity_signal: activity_signal specifies the activity. + + environment_id: The ID of the environment to update activity 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.EnvironmentService/MarkEnvironmentActive", + body=await async_maybe_transform( + { + "activity_signal": activity_signal, + "environment_id": environment_id, + }, + environment_mark_active_params.EnvironmentMarkActiveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def start( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Starts a stopped environment. + + Use this method to resume work on a previously stopped environment. The + environment retains its configuration and workspace content from when it was + stopped. + + ### Examples + + - Start an environment: + + Resumes a previously stopped environment with its existing configuration. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies which environment should be started. + + 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.EnvironmentService/StartEnvironment", + body=await async_maybe_transform( + {"environment_id": environment_id}, environment_start_params.EnvironmentStartParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def stop( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Stops a running environment. + + Use this method to pause work while preserving the environment's state. The + environment can be resumed later using StartEnvironment. + + ### Examples + + - Stop an environment: + + Gracefully stops a running environment while preserving its state. + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies which environment should be stopped. + + +required + + 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.EnvironmentService/StopEnvironment", + body=await async_maybe_transform( + {"environment_id": environment_id}, environment_stop_params.EnvironmentStopParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def unarchive( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Unarchives an environment. + + ### Examples + + - Unarchive an environment: + + ```yaml + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment to unarchive. + + +required + + 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.EnvironmentService/UnarchiveEnvironment", + body=await async_maybe_transform( + {"environment_id": environment_id}, environment_unarchive_params.EnvironmentUnarchiveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class EnvironmentsResourceWithRawResponse: + def __init__(self, environments: EnvironmentsResource) -> None: + self._environments = environments + + self.create = to_raw_response_wrapper( + environments.create, + ) + self.retrieve = to_raw_response_wrapper( + environments.retrieve, + ) + self.update = to_raw_response_wrapper( + environments.update, + ) + self.list = to_raw_response_wrapper( + environments.list, + ) + self.delete = to_raw_response_wrapper( + environments.delete, + ) + self.create_environment_token = to_raw_response_wrapper( + environments.create_environment_token, + ) + self.create_from_project = to_raw_response_wrapper( + environments.create_from_project, + ) + self.create_logs_token = to_raw_response_wrapper( + environments.create_logs_token, + ) + self.mark_active = to_raw_response_wrapper( + environments.mark_active, + ) + self.start = to_raw_response_wrapper( + environments.start, + ) + self.stop = to_raw_response_wrapper( + environments.stop, + ) + self.unarchive = to_raw_response_wrapper( + environments.unarchive, + ) + + @cached_property + def automations(self) -> AutomationsResourceWithRawResponse: + return AutomationsResourceWithRawResponse(self._environments.automations) + + @cached_property + def classes(self) -> ClassesResourceWithRawResponse: + return ClassesResourceWithRawResponse(self._environments.classes) + + +class AsyncEnvironmentsResourceWithRawResponse: + def __init__(self, environments: AsyncEnvironmentsResource) -> None: + self._environments = environments + + self.create = async_to_raw_response_wrapper( + environments.create, + ) + self.retrieve = async_to_raw_response_wrapper( + environments.retrieve, + ) + self.update = async_to_raw_response_wrapper( + environments.update, + ) + self.list = async_to_raw_response_wrapper( + environments.list, + ) + self.delete = async_to_raw_response_wrapper( + environments.delete, + ) + self.create_environment_token = async_to_raw_response_wrapper( + environments.create_environment_token, + ) + self.create_from_project = async_to_raw_response_wrapper( + environments.create_from_project, + ) + self.create_logs_token = async_to_raw_response_wrapper( + environments.create_logs_token, + ) + self.mark_active = async_to_raw_response_wrapper( + environments.mark_active, + ) + self.start = async_to_raw_response_wrapper( + environments.start, + ) + self.stop = async_to_raw_response_wrapper( + environments.stop, + ) + self.unarchive = async_to_raw_response_wrapper( + environments.unarchive, + ) + + @cached_property + def automations(self) -> AsyncAutomationsResourceWithRawResponse: + return AsyncAutomationsResourceWithRawResponse(self._environments.automations) + + @cached_property + def classes(self) -> AsyncClassesResourceWithRawResponse: + return AsyncClassesResourceWithRawResponse(self._environments.classes) + + +class EnvironmentsResourceWithStreamingResponse: + def __init__(self, environments: EnvironmentsResource) -> None: + self._environments = environments + + self.create = to_streamed_response_wrapper( + environments.create, + ) + self.retrieve = to_streamed_response_wrapper( + environments.retrieve, + ) + self.update = to_streamed_response_wrapper( + environments.update, + ) + self.list = to_streamed_response_wrapper( + environments.list, + ) + self.delete = to_streamed_response_wrapper( + environments.delete, + ) + self.create_environment_token = to_streamed_response_wrapper( + environments.create_environment_token, + ) + self.create_from_project = to_streamed_response_wrapper( + environments.create_from_project, + ) + self.create_logs_token = to_streamed_response_wrapper( + environments.create_logs_token, + ) + self.mark_active = to_streamed_response_wrapper( + environments.mark_active, + ) + self.start = to_streamed_response_wrapper( + environments.start, + ) + self.stop = to_streamed_response_wrapper( + environments.stop, + ) + self.unarchive = to_streamed_response_wrapper( + environments.unarchive, + ) + + @cached_property + def automations(self) -> AutomationsResourceWithStreamingResponse: + return AutomationsResourceWithStreamingResponse(self._environments.automations) + + @cached_property + def classes(self) -> ClassesResourceWithStreamingResponse: + return ClassesResourceWithStreamingResponse(self._environments.classes) + + +class AsyncEnvironmentsResourceWithStreamingResponse: + def __init__(self, environments: AsyncEnvironmentsResource) -> None: + self._environments = environments + + self.create = async_to_streamed_response_wrapper( + environments.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + environments.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + environments.update, + ) + self.list = async_to_streamed_response_wrapper( + environments.list, + ) + self.delete = async_to_streamed_response_wrapper( + environments.delete, + ) + self.create_environment_token = async_to_streamed_response_wrapper( + environments.create_environment_token, + ) + self.create_from_project = async_to_streamed_response_wrapper( + environments.create_from_project, + ) + self.create_logs_token = async_to_streamed_response_wrapper( + environments.create_logs_token, + ) + self.mark_active = async_to_streamed_response_wrapper( + environments.mark_active, + ) + self.start = async_to_streamed_response_wrapper( + environments.start, + ) + self.stop = async_to_streamed_response_wrapper( + environments.stop, + ) + self.unarchive = async_to_streamed_response_wrapper( + environments.unarchive, + ) + + @cached_property + def automations(self) -> AsyncAutomationsResourceWithStreamingResponse: + return AsyncAutomationsResourceWithStreamingResponse(self._environments.automations) + + @cached_property + def classes(self) -> AsyncClassesResourceWithStreamingResponse: + return AsyncClassesResourceWithStreamingResponse(self._environments.classes) diff --git a/src/gitpod/resources/events.py b/src/gitpod/resources/events.py new file mode 100644 index 0000000..b28929f --- /dev/null +++ b/src/gitpod/resources/events.py @@ -0,0 +1,402 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import event_list_params, event_watch_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncEntriesPage, AsyncEntriesPage +from .._base_client import AsyncPaginator, make_request_options +from .._decoders.jsonl import JSONLDecoder, AsyncJSONLDecoder +from ..types.event_list_response import EventListResponse +from ..types.event_watch_response import EventWatchResponse + +__all__ = ["EventsResource", "AsyncEventsResource"] + + +class EventsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> EventsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return EventsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> EventsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return EventsResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: event_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: event_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncEntriesPage[EventListResponse]: + """ + Lists audit logs with filtering and pagination options. + + Use this method to: + + - View audit history + - Track user actions + - Monitor system changes + + ### Examples + + - List all logs: + + ```yaml + pagination: + pageSize: 20 + ``` + + - Filter by actor: + + ```yaml + filter: + actorIds: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + actorPrincipals: ["PRINCIPAL_USER"] + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing environments + + 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._get_api_list( + "/gitpod.v1.EventService/ListAuditLogs", + page=SyncEntriesPage[EventListResponse], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + event_list_params.EventListParams, + ), + 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, + }, + event_list_params.EventListParams, + ), + ), + model=EventListResponse, + method="post", + ) + + def watch( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + organization: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> JSONLDecoder[EventWatchResponse]: + """ + Streams events for all projects, runners, environments, tasks, and services + based on the specified scope. + + Use this method to: + + - Monitor resource changes in real-time + - Track system events + - Receive notifications + + The scope parameter determines which events to watch: + + - Organization scope (default): Watch all organization-wide events including + projects, runners and environments. Task and service events are not included. + Use by setting organization=true or omitting the scope. + - Environment scope: Watch events for a specific environment, including its + tasks, task executions, and services. Use by setting environment_id to the + UUID of the environment to watch. + + Args: + environment_id: Environment scope produces events for the environment itself, all tasks, task + executions, and services associated with that environment. + + organization: Organization scope produces events for all projects, runners and environments + the caller can see within their organization. No task, task execution or service + events are produed. + + 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 + """ + extra_headers = {"Accept": "application/jsonl", **(extra_headers or {})} + return self._post( + "/gitpod.v1.EventService/WatchEvents", + body=maybe_transform( + { + "environment_id": environment_id, + "organization": organization, + }, + event_watch_params.EventWatchParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JSONLDecoder[EventWatchResponse], + stream=True, + ) + + +class AsyncEventsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncEventsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncEventsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncEventsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncEventsResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: event_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: event_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[EventListResponse, AsyncEntriesPage[EventListResponse]]: + """ + Lists audit logs with filtering and pagination options. + + Use this method to: + + - View audit history + - Track user actions + - Monitor system changes + + ### Examples + + - List all logs: + + ```yaml + pagination: + pageSize: 20 + ``` + + - Filter by actor: + + ```yaml + filter: + actorIds: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + actorPrincipals: ["PRINCIPAL_USER"] + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing environments + + 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._get_api_list( + "/gitpod.v1.EventService/ListAuditLogs", + page=AsyncEntriesPage[EventListResponse], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + event_list_params.EventListParams, + ), + 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, + }, + event_list_params.EventListParams, + ), + ), + model=EventListResponse, + method="post", + ) + + async def watch( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + organization: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncJSONLDecoder[EventWatchResponse]: + """ + Streams events for all projects, runners, environments, tasks, and services + based on the specified scope. + + Use this method to: + + - Monitor resource changes in real-time + - Track system events + - Receive notifications + + The scope parameter determines which events to watch: + + - Organization scope (default): Watch all organization-wide events including + projects, runners and environments. Task and service events are not included. + Use by setting organization=true or omitting the scope. + - Environment scope: Watch events for a specific environment, including its + tasks, task executions, and services. Use by setting environment_id to the + UUID of the environment to watch. + + Args: + environment_id: Environment scope produces events for the environment itself, all tasks, task + executions, and services associated with that environment. + + organization: Organization scope produces events for all projects, runners and environments + the caller can see within their organization. No task, task execution or service + events are produed. + + 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 + """ + extra_headers = {"Accept": "application/jsonl", **(extra_headers or {})} + return await self._post( + "/gitpod.v1.EventService/WatchEvents", + body=await async_maybe_transform( + { + "environment_id": environment_id, + "organization": organization, + }, + event_watch_params.EventWatchParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AsyncJSONLDecoder[EventWatchResponse], + stream=True, + ) + + +class EventsResourceWithRawResponse: + def __init__(self, events: EventsResource) -> None: + self._events = events + + self.list = to_raw_response_wrapper( + events.list, + ) + self.watch = to_raw_response_wrapper( + events.watch, + ) + + +class AsyncEventsResourceWithRawResponse: + def __init__(self, events: AsyncEventsResource) -> None: + self._events = events + + self.list = async_to_raw_response_wrapper( + events.list, + ) + self.watch = async_to_raw_response_wrapper( + events.watch, + ) + + +class EventsResourceWithStreamingResponse: + def __init__(self, events: EventsResource) -> None: + self._events = events + + self.list = to_streamed_response_wrapper( + events.list, + ) + self.watch = to_streamed_response_wrapper( + events.watch, + ) + + +class AsyncEventsResourceWithStreamingResponse: + def __init__(self, events: AsyncEventsResource) -> None: + self._events = events + + self.list = async_to_streamed_response_wrapper( + events.list, + ) + self.watch = async_to_streamed_response_wrapper( + events.watch, + ) diff --git a/src/gitpod/resources/gateways.py b/src/gitpod/resources/gateways.py new file mode 100644 index 0000000..9351d6a --- /dev/null +++ b/src/gitpod/resources/gateways.py @@ -0,0 +1,196 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import gateway_list_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncGatewaysPage, AsyncGatewaysPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.shared.gateway import Gateway + +__all__ = ["GatewaysResource", "AsyncGatewaysResource"] + + +class GatewaysResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> GatewaysResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return GatewaysResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GatewaysResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return GatewaysResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: gateway_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncGatewaysPage[Gateway]: + """ + ListGateways + + Args: + pagination: pagination contains the pagination options for listing gateways + + 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._get_api_list( + "/gitpod.v1.GatewayService/ListGateways", + page=SyncGatewaysPage[Gateway], + body=maybe_transform({"pagination": pagination}, gateway_list_params.GatewayListParams), + 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, + }, + gateway_list_params.GatewayListParams, + ), + ), + model=Gateway, + method="post", + ) + + +class AsyncGatewaysResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncGatewaysResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncGatewaysResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGatewaysResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncGatewaysResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: gateway_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Gateway, AsyncGatewaysPage[Gateway]]: + """ + ListGateways + + Args: + pagination: pagination contains the pagination options for listing gateways + + 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._get_api_list( + "/gitpod.v1.GatewayService/ListGateways", + page=AsyncGatewaysPage[Gateway], + body=maybe_transform({"pagination": pagination}, gateway_list_params.GatewayListParams), + 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, + }, + gateway_list_params.GatewayListParams, + ), + ), + model=Gateway, + method="post", + ) + + +class GatewaysResourceWithRawResponse: + def __init__(self, gateways: GatewaysResource) -> None: + self._gateways = gateways + + self.list = to_raw_response_wrapper( + gateways.list, + ) + + +class AsyncGatewaysResourceWithRawResponse: + def __init__(self, gateways: AsyncGatewaysResource) -> None: + self._gateways = gateways + + self.list = async_to_raw_response_wrapper( + gateways.list, + ) + + +class GatewaysResourceWithStreamingResponse: + def __init__(self, gateways: GatewaysResource) -> None: + self._gateways = gateways + + self.list = to_streamed_response_wrapper( + gateways.list, + ) + + +class AsyncGatewaysResourceWithStreamingResponse: + def __init__(self, gateways: AsyncGatewaysResource) -> None: + self._gateways = gateways + + self.list = async_to_streamed_response_wrapper( + gateways.list, + ) diff --git a/src/gitpod/resources/groups.py b/src/gitpod/resources/groups.py new file mode 100644 index 0000000..56c681f --- /dev/null +++ b/src/gitpod/resources/groups.py @@ -0,0 +1,252 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import group_list_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncGroupsPage, AsyncGroupsPage +from ..types.group import Group +from .._base_client import AsyncPaginator, make_request_options + +__all__ = ["GroupsResource", "AsyncGroupsResource"] + + +class GroupsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> GroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return GroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return GroupsResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: group_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncGroupsPage[Group]: + """ + Lists groups with optional pagination. + + Use this method to: + + - View all groups + - Check group memberships + - Monitor group configurations + - Audit group access + + ### Examples + + - List all groups: + + Shows all groups with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + - List with custom page size: + + Shows groups with specified page size. + + ```yaml + pagination: + pageSize: 50 + token: "next-page-token-from-previous-response" + ``` + + Args: + pagination: pagination contains the pagination options for listing groups + + 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._get_api_list( + "/gitpod.v1.GroupService/ListGroups", + page=SyncGroupsPage[Group], + body=maybe_transform({"pagination": pagination}, group_list_params.GroupListParams), + 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, + }, + group_list_params.GroupListParams, + ), + ), + model=Group, + method="post", + ) + + +class AsyncGroupsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncGroupsResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: group_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Group, AsyncGroupsPage[Group]]: + """ + Lists groups with optional pagination. + + Use this method to: + + - View all groups + - Check group memberships + - Monitor group configurations + - Audit group access + + ### Examples + + - List all groups: + + Shows all groups with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + - List with custom page size: + + Shows groups with specified page size. + + ```yaml + pagination: + pageSize: 50 + token: "next-page-token-from-previous-response" + ``` + + Args: + pagination: pagination contains the pagination options for listing groups + + 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._get_api_list( + "/gitpod.v1.GroupService/ListGroups", + page=AsyncGroupsPage[Group], + body=maybe_transform({"pagination": pagination}, group_list_params.GroupListParams), + 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, + }, + group_list_params.GroupListParams, + ), + ), + model=Group, + method="post", + ) + + +class GroupsResourceWithRawResponse: + def __init__(self, groups: GroupsResource) -> None: + self._groups = groups + + self.list = to_raw_response_wrapper( + groups.list, + ) + + +class AsyncGroupsResourceWithRawResponse: + def __init__(self, groups: AsyncGroupsResource) -> None: + self._groups = groups + + self.list = async_to_raw_response_wrapper( + groups.list, + ) + + +class GroupsResourceWithStreamingResponse: + def __init__(self, groups: GroupsResource) -> None: + self._groups = groups + + self.list = to_streamed_response_wrapper( + groups.list, + ) + + +class AsyncGroupsResourceWithStreamingResponse: + def __init__(self, groups: AsyncGroupsResource) -> None: + self._groups = groups + + self.list = async_to_streamed_response_wrapper( + groups.list, + ) diff --git a/src/gitpod/resources/identity.py b/src/gitpod/resources/identity.py new file mode 100644 index 0000000..25b859b --- /dev/null +++ b/src/gitpod/resources/identity.py @@ -0,0 +1,475 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List + +import httpx + +from ..types import ( + IDTokenVersion, + identity_get_id_token_params, + identity_exchange_token_params, + identity_get_authenticated_identity_params, +) +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.id_token_version import IDTokenVersion +from ..types.identity_get_id_token_response import IdentityGetIDTokenResponse +from ..types.identity_exchange_token_response import IdentityExchangeTokenResponse +from ..types.identity_get_authenticated_identity_response import IdentityGetAuthenticatedIdentityResponse + +__all__ = ["IdentityResource", "AsyncIdentityResource"] + + +class IdentityResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> IdentityResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return IdentityResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> IdentityResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return IdentityResourceWithStreamingResponse(self) + + def exchange_token( + self, + *, + exchange_token: str | NotGiven = NOT_GIVEN, + # 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, + ) -> IdentityExchangeTokenResponse: + """ + Exchanges an exchange token for a new access token. + + Use this method to: + + - Convert exchange tokens to access tokens + - Obtain new access credentials + - Complete token exchange flows + + ### Examples + + - Exchange token: + + Trades an exchange token for an access token. + + ```yaml + exchangeToken: "exchange-token-value" + ``` + + Args: + exchange_token: exchange_token is the token to exchange + + 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.IdentityService/ExchangeToken", + body=maybe_transform( + {"exchange_token": exchange_token}, identity_exchange_token_params.IdentityExchangeTokenParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=IdentityExchangeTokenResponse, + ) + + def get_authenticated_identity( + self, + *, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> IdentityGetAuthenticatedIdentityResponse: + """ + Retrieves information about the currently authenticated identity. + + Use this method to: + + - Get current user information + - Check authentication status + - Retrieve organization context + - Validate authentication principal + + ### Examples + + - Get current identity: + + Retrieves details about the authenticated user. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.IdentityService/GetAuthenticatedIdentity", + body=maybe_transform( + {"empty": empty}, identity_get_authenticated_identity_params.IdentityGetAuthenticatedIdentityParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=IdentityGetAuthenticatedIdentityResponse, + ) + + def get_id_token( + self, + *, + audience: List[str] | NotGiven = NOT_GIVEN, + version: IDTokenVersion | NotGiven = NOT_GIVEN, + # 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, + ) -> IdentityGetIDTokenResponse: + """ + Gets an ID token for authenticating with other services. + + Use this method to: + + - Obtain authentication tokens for service-to-service calls + - Access protected resources + - Generate scoped access tokens + + ### Examples + + - Get token for single service: + + Retrieves a token for authenticating with one service. + + ```yaml + audience: + - "https://api.gitpod.io" + ``` + + - Get token for multiple services: + + Retrieves a token valid for multiple services. + + ```yaml + audience: + - "https://api.gitpod.io" + - "https://ws.gitpod.io" + ``` + + Args: + version: version is the version of the ID token. + + 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.IdentityService/GetIDToken", + body=maybe_transform( + { + "audience": audience, + "version": version, + }, + identity_get_id_token_params.IdentityGetIDTokenParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=IdentityGetIDTokenResponse, + ) + + +class AsyncIdentityResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncIdentityResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncIdentityResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncIdentityResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncIdentityResourceWithStreamingResponse(self) + + async def exchange_token( + self, + *, + exchange_token: str | NotGiven = NOT_GIVEN, + # 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, + ) -> IdentityExchangeTokenResponse: + """ + Exchanges an exchange token for a new access token. + + Use this method to: + + - Convert exchange tokens to access tokens + - Obtain new access credentials + - Complete token exchange flows + + ### Examples + + - Exchange token: + + Trades an exchange token for an access token. + + ```yaml + exchangeToken: "exchange-token-value" + ``` + + Args: + exchange_token: exchange_token is the token to exchange + + 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.IdentityService/ExchangeToken", + body=await async_maybe_transform( + {"exchange_token": exchange_token}, identity_exchange_token_params.IdentityExchangeTokenParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=IdentityExchangeTokenResponse, + ) + + async def get_authenticated_identity( + self, + *, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> IdentityGetAuthenticatedIdentityResponse: + """ + Retrieves information about the currently authenticated identity. + + Use this method to: + + - Get current user information + - Check authentication status + - Retrieve organization context + - Validate authentication principal + + ### Examples + + - Get current identity: + + Retrieves details about the authenticated user. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.IdentityService/GetAuthenticatedIdentity", + body=await async_maybe_transform( + {"empty": empty}, identity_get_authenticated_identity_params.IdentityGetAuthenticatedIdentityParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=IdentityGetAuthenticatedIdentityResponse, + ) + + async def get_id_token( + self, + *, + audience: List[str] | NotGiven = NOT_GIVEN, + version: IDTokenVersion | NotGiven = NOT_GIVEN, + # 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, + ) -> IdentityGetIDTokenResponse: + """ + Gets an ID token for authenticating with other services. + + Use this method to: + + - Obtain authentication tokens for service-to-service calls + - Access protected resources + - Generate scoped access tokens + + ### Examples + + - Get token for single service: + + Retrieves a token for authenticating with one service. + + ```yaml + audience: + - "https://api.gitpod.io" + ``` + + - Get token for multiple services: + + Retrieves a token valid for multiple services. + + ```yaml + audience: + - "https://api.gitpod.io" + - "https://ws.gitpod.io" + ``` + + Args: + version: version is the version of the ID token. + + 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.IdentityService/GetIDToken", + body=await async_maybe_transform( + { + "audience": audience, + "version": version, + }, + identity_get_id_token_params.IdentityGetIDTokenParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=IdentityGetIDTokenResponse, + ) + + +class IdentityResourceWithRawResponse: + def __init__(self, identity: IdentityResource) -> None: + self._identity = identity + + self.exchange_token = to_raw_response_wrapper( + identity.exchange_token, + ) + self.get_authenticated_identity = to_raw_response_wrapper( + identity.get_authenticated_identity, + ) + self.get_id_token = to_raw_response_wrapper( + identity.get_id_token, + ) + + +class AsyncIdentityResourceWithRawResponse: + def __init__(self, identity: AsyncIdentityResource) -> None: + self._identity = identity + + self.exchange_token = async_to_raw_response_wrapper( + identity.exchange_token, + ) + self.get_authenticated_identity = async_to_raw_response_wrapper( + identity.get_authenticated_identity, + ) + self.get_id_token = async_to_raw_response_wrapper( + identity.get_id_token, + ) + + +class IdentityResourceWithStreamingResponse: + def __init__(self, identity: IdentityResource) -> None: + self._identity = identity + + self.exchange_token = to_streamed_response_wrapper( + identity.exchange_token, + ) + self.get_authenticated_identity = to_streamed_response_wrapper( + identity.get_authenticated_identity, + ) + self.get_id_token = to_streamed_response_wrapper( + identity.get_id_token, + ) + + +class AsyncIdentityResourceWithStreamingResponse: + def __init__(self, identity: AsyncIdentityResource) -> None: + self._identity = identity + + self.exchange_token = async_to_streamed_response_wrapper( + identity.exchange_token, + ) + self.get_authenticated_identity = async_to_streamed_response_wrapper( + identity.get_authenticated_identity, + ) + self.get_id_token = async_to_streamed_response_wrapper( + identity.get_id_token, + ) diff --git a/src/gitpod/resources/organizations/__init__.py b/src/gitpod/resources/organizations/__init__.py new file mode 100644 index 0000000..28e5eed --- /dev/null +++ b/src/gitpod/resources/organizations/__init__.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .invites import ( + InvitesResource, + AsyncInvitesResource, + InvitesResourceWithRawResponse, + AsyncInvitesResourceWithRawResponse, + InvitesResourceWithStreamingResponse, + AsyncInvitesResourceWithStreamingResponse, +) +from .policies import ( + PoliciesResource, + AsyncPoliciesResource, + PoliciesResourceWithRawResponse, + AsyncPoliciesResourceWithRawResponse, + PoliciesResourceWithStreamingResponse, + AsyncPoliciesResourceWithStreamingResponse, +) +from .organizations import ( + OrganizationsResource, + AsyncOrganizationsResource, + OrganizationsResourceWithRawResponse, + AsyncOrganizationsResourceWithRawResponse, + OrganizationsResourceWithStreamingResponse, + AsyncOrganizationsResourceWithStreamingResponse, +) +from .sso_configurations import ( + SSOConfigurationsResource, + AsyncSSOConfigurationsResource, + SSOConfigurationsResourceWithRawResponse, + AsyncSSOConfigurationsResourceWithRawResponse, + SSOConfigurationsResourceWithStreamingResponse, + AsyncSSOConfigurationsResourceWithStreamingResponse, +) +from .domain_verifications import ( + DomainVerificationsResource, + AsyncDomainVerificationsResource, + DomainVerificationsResourceWithRawResponse, + AsyncDomainVerificationsResourceWithRawResponse, + DomainVerificationsResourceWithStreamingResponse, + AsyncDomainVerificationsResourceWithStreamingResponse, +) + +__all__ = [ + "DomainVerificationsResource", + "AsyncDomainVerificationsResource", + "DomainVerificationsResourceWithRawResponse", + "AsyncDomainVerificationsResourceWithRawResponse", + "DomainVerificationsResourceWithStreamingResponse", + "AsyncDomainVerificationsResourceWithStreamingResponse", + "InvitesResource", + "AsyncInvitesResource", + "InvitesResourceWithRawResponse", + "AsyncInvitesResourceWithRawResponse", + "InvitesResourceWithStreamingResponse", + "AsyncInvitesResourceWithStreamingResponse", + "PoliciesResource", + "AsyncPoliciesResource", + "PoliciesResourceWithRawResponse", + "AsyncPoliciesResourceWithRawResponse", + "PoliciesResourceWithStreamingResponse", + "AsyncPoliciesResourceWithStreamingResponse", + "SSOConfigurationsResource", + "AsyncSSOConfigurationsResource", + "SSOConfigurationsResourceWithRawResponse", + "AsyncSSOConfigurationsResourceWithRawResponse", + "SSOConfigurationsResourceWithStreamingResponse", + "AsyncSSOConfigurationsResourceWithStreamingResponse", + "OrganizationsResource", + "AsyncOrganizationsResource", + "OrganizationsResourceWithRawResponse", + "AsyncOrganizationsResourceWithRawResponse", + "OrganizationsResourceWithStreamingResponse", + "AsyncOrganizationsResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/organizations/domain_verifications.py b/src/gitpod/resources/organizations/domain_verifications.py new file mode 100644 index 0000000..5468ac8 --- /dev/null +++ b/src/gitpod/resources/organizations/domain_verifications.py @@ -0,0 +1,761 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncDomainVerificationsPage, AsyncDomainVerificationsPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.organizations import ( + domain_verification_list_params, + domain_verification_create_params, + domain_verification_delete_params, + domain_verification_verify_params, + domain_verification_retrieve_params, +) +from ...types.organizations.domain_verification import DomainVerification +from ...types.organizations.domain_verification_create_response import DomainVerificationCreateResponse +from ...types.organizations.domain_verification_verify_response import DomainVerificationVerifyResponse +from ...types.organizations.domain_verification_retrieve_response import DomainVerificationRetrieveResponse + +__all__ = ["DomainVerificationsResource", "AsyncDomainVerificationsResource"] + + +class DomainVerificationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DomainVerificationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return DomainVerificationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DomainVerificationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return DomainVerificationsResourceWithStreamingResponse(self) + + def create( + self, + *, + domain: str, + organization_id: str, + # 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, + ) -> DomainVerificationCreateResponse: + """ + Initiates domain verification process to enable organization features. + + Use this method to: + + - Start domain ownership verification + - Enable automatic team joining + - Set up SSO restrictions + - Configure email-based policies + + ### Examples + + - Verify primary domain: + + Starts verification for main company domain. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + domain: "acme-corp.com" + ``` + + - Verify subsidiary domain: + + Adds verification for additional company domain. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + domain: "acme-subsidiary.com" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/CreateDomainVerification", + body=maybe_transform( + { + "domain": domain, + "organization_id": organization_id, + }, + domain_verification_create_params.DomainVerificationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DomainVerificationCreateResponse, + ) + + def retrieve( + self, + *, + domain_verification_id: str, + # 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, + ) -> DomainVerificationRetrieveResponse: + """ + Retrieves the status of a domain verification request. + + Use this method to: + + - Check verification progress + - View verification requirements + - Monitor domain status + + ### Examples + + - Get verification status: + + Checks the current state of a domain verification. + + ```yaml + domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/GetDomainVerification", + body=maybe_transform( + {"domain_verification_id": domain_verification_id}, + domain_verification_retrieve_params.DomainVerificationRetrieveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DomainVerificationRetrieveResponse, + ) + + def list( + self, + *, + organization_id: str, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: domain_verification_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncDomainVerificationsPage[DomainVerification]: + """ + Lists and monitors domain verification status across an organization. + + Use this method to: + + - Track verification progress + - View all verified domains + - Monitor pending verifications + - Audit domain settings + + ### Examples + + - List all verifications: + + Shows all domain verifications regardless of status. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + - List with pagination: + + Retrieves next page of verifications. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + token: "next-page-token-from-previous-response" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/gitpod.v1.OrganizationService/ListDomainVerifications", + page=SyncDomainVerificationsPage[DomainVerification], + body=maybe_transform( + { + "organization_id": organization_id, + "pagination": pagination, + }, + domain_verification_list_params.DomainVerificationListParams, + ), + 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, + }, + domain_verification_list_params.DomainVerificationListParams, + ), + ), + model=DomainVerification, + method="post", + ) + + def delete( + self, + *, + domain_verification_id: str, + # 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, + ) -> object: + """ + Removes a domain verification request. + + Use this method to: + + - Cancel pending verifications + - Remove verified domains + - Clean up unused domain records + + ### Examples + + - Delete verification: + + Removes a domain verification request. + + ```yaml + domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/DeleteDomainVerification", + body=maybe_transform( + {"domain_verification_id": domain_verification_id}, + domain_verification_delete_params.DomainVerificationDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def verify( + self, + *, + domain_verification_id: str, + # 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, + ) -> DomainVerificationVerifyResponse: + """ + Verifies domain ownership for an organization. + + Use this method to: + + - Complete domain verification process + - Enable domain-based features + - Validate DNS configuration + + ### Examples + + - Verify domain ownership: + + Verifies ownership after DNS records are configured. + + ```yaml + domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/VerifyDomain", + body=maybe_transform( + {"domain_verification_id": domain_verification_id}, + domain_verification_verify_params.DomainVerificationVerifyParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DomainVerificationVerifyResponse, + ) + + +class AsyncDomainVerificationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDomainVerificationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncDomainVerificationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDomainVerificationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncDomainVerificationsResourceWithStreamingResponse(self) + + async def create( + self, + *, + domain: str, + organization_id: str, + # 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, + ) -> DomainVerificationCreateResponse: + """ + Initiates domain verification process to enable organization features. + + Use this method to: + + - Start domain ownership verification + - Enable automatic team joining + - Set up SSO restrictions + - Configure email-based policies + + ### Examples + + - Verify primary domain: + + Starts verification for main company domain. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + domain: "acme-corp.com" + ``` + + - Verify subsidiary domain: + + Adds verification for additional company domain. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + domain: "acme-subsidiary.com" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/CreateDomainVerification", + body=await async_maybe_transform( + { + "domain": domain, + "organization_id": organization_id, + }, + domain_verification_create_params.DomainVerificationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DomainVerificationCreateResponse, + ) + + async def retrieve( + self, + *, + domain_verification_id: str, + # 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, + ) -> DomainVerificationRetrieveResponse: + """ + Retrieves the status of a domain verification request. + + Use this method to: + + - Check verification progress + - View verification requirements + - Monitor domain status + + ### Examples + + - Get verification status: + + Checks the current state of a domain verification. + + ```yaml + domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/GetDomainVerification", + body=await async_maybe_transform( + {"domain_verification_id": domain_verification_id}, + domain_verification_retrieve_params.DomainVerificationRetrieveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DomainVerificationRetrieveResponse, + ) + + def list( + self, + *, + organization_id: str, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: domain_verification_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[DomainVerification, AsyncDomainVerificationsPage[DomainVerification]]: + """ + Lists and monitors domain verification status across an organization. + + Use this method to: + + - Track verification progress + - View all verified domains + - Monitor pending verifications + - Audit domain settings + + ### Examples + + - List all verifications: + + Shows all domain verifications regardless of status. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + - List with pagination: + + Retrieves next page of verifications. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + token: "next-page-token-from-previous-response" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/gitpod.v1.OrganizationService/ListDomainVerifications", + page=AsyncDomainVerificationsPage[DomainVerification], + body=maybe_transform( + { + "organization_id": organization_id, + "pagination": pagination, + }, + domain_verification_list_params.DomainVerificationListParams, + ), + 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, + }, + domain_verification_list_params.DomainVerificationListParams, + ), + ), + model=DomainVerification, + method="post", + ) + + async def delete( + self, + *, + domain_verification_id: str, + # 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, + ) -> object: + """ + Removes a domain verification request. + + Use this method to: + + - Cancel pending verifications + - Remove verified domains + - Clean up unused domain records + + ### Examples + + - Delete verification: + + Removes a domain verification request. + + ```yaml + domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/DeleteDomainVerification", + body=await async_maybe_transform( + {"domain_verification_id": domain_verification_id}, + domain_verification_delete_params.DomainVerificationDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def verify( + self, + *, + domain_verification_id: str, + # 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, + ) -> DomainVerificationVerifyResponse: + """ + Verifies domain ownership for an organization. + + Use this method to: + + - Complete domain verification process + - Enable domain-based features + - Validate DNS configuration + + ### Examples + + - Verify domain ownership: + + Verifies ownership after DNS records are configured. + + ```yaml + domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/VerifyDomain", + body=await async_maybe_transform( + {"domain_verification_id": domain_verification_id}, + domain_verification_verify_params.DomainVerificationVerifyParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DomainVerificationVerifyResponse, + ) + + +class DomainVerificationsResourceWithRawResponse: + def __init__(self, domain_verifications: DomainVerificationsResource) -> None: + self._domain_verifications = domain_verifications + + self.create = to_raw_response_wrapper( + domain_verifications.create, + ) + self.retrieve = to_raw_response_wrapper( + domain_verifications.retrieve, + ) + self.list = to_raw_response_wrapper( + domain_verifications.list, + ) + self.delete = to_raw_response_wrapper( + domain_verifications.delete, + ) + self.verify = to_raw_response_wrapper( + domain_verifications.verify, + ) + + +class AsyncDomainVerificationsResourceWithRawResponse: + def __init__(self, domain_verifications: AsyncDomainVerificationsResource) -> None: + self._domain_verifications = domain_verifications + + self.create = async_to_raw_response_wrapper( + domain_verifications.create, + ) + self.retrieve = async_to_raw_response_wrapper( + domain_verifications.retrieve, + ) + self.list = async_to_raw_response_wrapper( + domain_verifications.list, + ) + self.delete = async_to_raw_response_wrapper( + domain_verifications.delete, + ) + self.verify = async_to_raw_response_wrapper( + domain_verifications.verify, + ) + + +class DomainVerificationsResourceWithStreamingResponse: + def __init__(self, domain_verifications: DomainVerificationsResource) -> None: + self._domain_verifications = domain_verifications + + self.create = to_streamed_response_wrapper( + domain_verifications.create, + ) + self.retrieve = to_streamed_response_wrapper( + domain_verifications.retrieve, + ) + self.list = to_streamed_response_wrapper( + domain_verifications.list, + ) + self.delete = to_streamed_response_wrapper( + domain_verifications.delete, + ) + self.verify = to_streamed_response_wrapper( + domain_verifications.verify, + ) + + +class AsyncDomainVerificationsResourceWithStreamingResponse: + def __init__(self, domain_verifications: AsyncDomainVerificationsResource) -> None: + self._domain_verifications = domain_verifications + + self.create = async_to_streamed_response_wrapper( + domain_verifications.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + domain_verifications.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + domain_verifications.list, + ) + self.delete = async_to_streamed_response_wrapper( + domain_verifications.delete, + ) + self.verify = async_to_streamed_response_wrapper( + domain_verifications.verify, + ) diff --git a/src/gitpod/resources/organizations/invites.py b/src/gitpod/resources/organizations/invites.py new file mode 100644 index 0000000..8ed2e02 --- /dev/null +++ b/src/gitpod/resources/organizations/invites.py @@ -0,0 +1,393 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.organizations import invite_create_params, invite_retrieve_params, invite_get_summary_params +from ...types.organizations.invite_create_response import InviteCreateResponse +from ...types.organizations.invite_retrieve_response import InviteRetrieveResponse +from ...types.organizations.invite_get_summary_response import InviteGetSummaryResponse + +__all__ = ["InvitesResource", "AsyncInvitesResource"] + + +class InvitesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InvitesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return InvitesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InvitesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return InvitesResourceWithStreamingResponse(self) + + def create( + self, + *, + organization_id: str, + # 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, + ) -> InviteCreateResponse: + """Creates an invite link for joining an organization. + + Any existing + OrganizationInvites are invalidated and can no longer be used. + + Use this method to: + + - Generate shareable invite links + - Manage team growth + - Control organization access + + ### Examples + + - Create organization invite: + + Generates a new invite link for the organization. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/CreateOrganizationInvite", + body=maybe_transform({"organization_id": organization_id}, invite_create_params.InviteCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InviteCreateResponse, + ) + + def retrieve( + self, + *, + organization_id: str, + # 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, + ) -> InviteRetrieveResponse: + """ + GetOrganizationInvite + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/GetOrganizationInvite", + body=maybe_transform({"organization_id": organization_id}, invite_retrieve_params.InviteRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InviteRetrieveResponse, + ) + + def get_summary( + self, + *, + invite_id: str, + # 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, + ) -> InviteGetSummaryResponse: + """ + Retrieves organization details and membership info based on an invite link. + + Use this method to: + + - Preview organization details before joining + - Validate invite link authenticity + - Check organization size and activity + - View team information before accepting + + ### Examples + + - Get invite summary: + + Retrieves organization information from an invite. + + ```yaml + inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/GetOrganizationInviteSummary", + body=maybe_transform({"invite_id": invite_id}, invite_get_summary_params.InviteGetSummaryParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InviteGetSummaryResponse, + ) + + +class AsyncInvitesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInvitesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncInvitesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInvitesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncInvitesResourceWithStreamingResponse(self) + + async def create( + self, + *, + organization_id: str, + # 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, + ) -> InviteCreateResponse: + """Creates an invite link for joining an organization. + + Any existing + OrganizationInvites are invalidated and can no longer be used. + + Use this method to: + + - Generate shareable invite links + - Manage team growth + - Control organization access + + ### Examples + + - Create organization invite: + + Generates a new invite link for the organization. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/CreateOrganizationInvite", + body=await async_maybe_transform( + {"organization_id": organization_id}, invite_create_params.InviteCreateParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InviteCreateResponse, + ) + + async def retrieve( + self, + *, + organization_id: str, + # 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, + ) -> InviteRetrieveResponse: + """ + GetOrganizationInvite + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/GetOrganizationInvite", + body=await async_maybe_transform( + {"organization_id": organization_id}, invite_retrieve_params.InviteRetrieveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InviteRetrieveResponse, + ) + + async def get_summary( + self, + *, + invite_id: str, + # 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, + ) -> InviteGetSummaryResponse: + """ + Retrieves organization details and membership info based on an invite link. + + Use this method to: + + - Preview organization details before joining + - Validate invite link authenticity + - Check organization size and activity + - View team information before accepting + + ### Examples + + - Get invite summary: + + Retrieves organization information from an invite. + + ```yaml + inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/GetOrganizationInviteSummary", + body=await async_maybe_transform( + {"invite_id": invite_id}, invite_get_summary_params.InviteGetSummaryParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InviteGetSummaryResponse, + ) + + +class InvitesResourceWithRawResponse: + def __init__(self, invites: InvitesResource) -> None: + self._invites = invites + + self.create = to_raw_response_wrapper( + invites.create, + ) + self.retrieve = to_raw_response_wrapper( + invites.retrieve, + ) + self.get_summary = to_raw_response_wrapper( + invites.get_summary, + ) + + +class AsyncInvitesResourceWithRawResponse: + def __init__(self, invites: AsyncInvitesResource) -> None: + self._invites = invites + + self.create = async_to_raw_response_wrapper( + invites.create, + ) + self.retrieve = async_to_raw_response_wrapper( + invites.retrieve, + ) + self.get_summary = async_to_raw_response_wrapper( + invites.get_summary, + ) + + +class InvitesResourceWithStreamingResponse: + def __init__(self, invites: InvitesResource) -> None: + self._invites = invites + + self.create = to_streamed_response_wrapper( + invites.create, + ) + self.retrieve = to_streamed_response_wrapper( + invites.retrieve, + ) + self.get_summary = to_streamed_response_wrapper( + invites.get_summary, + ) + + +class AsyncInvitesResourceWithStreamingResponse: + def __init__(self, invites: AsyncInvitesResource) -> None: + self._invites = invites + + self.create = async_to_streamed_response_wrapper( + invites.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + invites.retrieve, + ) + self.get_summary = async_to_streamed_response_wrapper( + invites.get_summary, + ) diff --git a/src/gitpod/resources/organizations/organizations.py b/src/gitpod/resources/organizations/organizations.py new file mode 100644 index 0000000..0e989d8 --- /dev/null +++ b/src/gitpod/resources/organizations/organizations.py @@ -0,0 +1,1401 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ...types import ( + organization_join_params, + organization_leave_params, + organization_create_params, + organization_delete_params, + organization_update_params, + organization_retrieve_params, + organization_set_role_params, + organization_list_members_params, +) +from .invites import ( + InvitesResource, + AsyncInvitesResource, + InvitesResourceWithRawResponse, + AsyncInvitesResourceWithRawResponse, + InvitesResourceWithStreamingResponse, + AsyncInvitesResourceWithStreamingResponse, +) +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from .policies import ( + PoliciesResource, + AsyncPoliciesResource, + PoliciesResourceWithRawResponse, + AsyncPoliciesResourceWithRawResponse, + PoliciesResourceWithStreamingResponse, + AsyncPoliciesResourceWithStreamingResponse, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncMembersPage, AsyncMembersPage +from ..._base_client import AsyncPaginator, make_request_options +from .sso_configurations import ( + SSOConfigurationsResource, + AsyncSSOConfigurationsResource, + SSOConfigurationsResourceWithRawResponse, + AsyncSSOConfigurationsResourceWithRawResponse, + SSOConfigurationsResourceWithStreamingResponse, + AsyncSSOConfigurationsResourceWithStreamingResponse, +) +from .domain_verifications import ( + DomainVerificationsResource, + AsyncDomainVerificationsResource, + DomainVerificationsResourceWithRawResponse, + AsyncDomainVerificationsResourceWithRawResponse, + DomainVerificationsResourceWithStreamingResponse, + AsyncDomainVerificationsResourceWithStreamingResponse, +) +from ...types.organization_member import OrganizationMember +from ...types.invite_domains_param import InviteDomainsParam +from ...types.shared.organization_role import OrganizationRole +from ...types.organization_join_response import OrganizationJoinResponse +from ...types.organization_create_response import OrganizationCreateResponse +from ...types.organization_update_response import OrganizationUpdateResponse +from ...types.organization_retrieve_response import OrganizationRetrieveResponse + +__all__ = ["OrganizationsResource", "AsyncOrganizationsResource"] + + +class OrganizationsResource(SyncAPIResource): + @cached_property + def domain_verifications(self) -> DomainVerificationsResource: + return DomainVerificationsResource(self._client) + + @cached_property + def invites(self) -> InvitesResource: + return InvitesResource(self._client) + + @cached_property + def policies(self) -> PoliciesResource: + return PoliciesResource(self._client) + + @cached_property + def sso_configurations(self) -> SSOConfigurationsResource: + return SSOConfigurationsResource(self._client) + + @cached_property + def with_raw_response(self) -> OrganizationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return OrganizationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OrganizationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return OrganizationsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + invite_accounts_with_matching_domain: bool | NotGiven = NOT_GIVEN, + join_organization: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> OrganizationCreateResponse: + """ + Creates a new organization with the specified name and settings. + + Use this method to: + + - Create a new organization for team collaboration + - Set up automatic domain-based invites for team members + - Join the organization immediately upon creation + + ### Examples + + - Create a basic organization: + + Creates an organization with just a name. + + ```yaml + name: "Acme Corp Engineering" + joinOrganization: true + ``` + + - Create with domain-based invites: + + Creates an organization that automatically invites users with matching email + domains. + + ```yaml + name: "Acme Corp" + joinOrganization: true + inviteAccountsWithMatchingDomain: true + ``` + + Args: + name: name is the organization name + + invite_accounts_with_matching_domain: Should other Accounts with the same domain be automatically invited to the + organization? + + join_organization: join_organization decides whether the Identity issuing this request joins the + org on creation + + 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.OrganizationService/CreateOrganization", + body=maybe_transform( + { + "name": name, + "invite_accounts_with_matching_domain": invite_accounts_with_matching_domain, + "join_organization": join_organization, + }, + organization_create_params.OrganizationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrganizationCreateResponse, + ) + + def retrieve( + self, + *, + organization_id: str, + # 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, + ) -> OrganizationRetrieveResponse: + """ + Gets details about a specific organization. + + Use this method to: + + - Retrieve organization settings and configuration + - Check organization membership status + - View domain verification settings + + ### Examples + + - Get organization details: + + Retrieves information about a specific organization. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + organization_id: organization_id is the unique identifier of the Organization to retreive. + + 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.OrganizationService/GetOrganization", + body=maybe_transform( + {"organization_id": organization_id}, organization_retrieve_params.OrganizationRetrieveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrganizationRetrieveResponse, + ) + + def update( + self, + *, + organization_id: str, + invite_domains: Optional[InviteDomainsParam] | NotGiven = NOT_GIVEN, + name: Optional[str] | NotGiven = NOT_GIVEN, + # 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, + ) -> OrganizationUpdateResponse: + """ + Updates an organization's settings including name, invite domains, and member + policies. + + Use this method to: + + - Modify organization display name + - Configure email domain restrictions + - Update organization-wide settings + - Manage member access policies + + ### Examples + + - Update basic settings: + + Changes organization name and invite domains. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + name: "New Company Name" + inviteDomains: + domains: + - "company.com" + - "subsidiary.com" + ``` + + - Remove domain restrictions: + + Clears all domain-based invite restrictions. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + inviteDomains: + domains: [] + ``` + + Args: + organization_id: organization_id is the ID of the organization to update the settings for. + + invite_domains: invite_domains is the domain allowlist of the organization + + name: name is the new name of the organization + + 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.OrganizationService/UpdateOrganization", + body=maybe_transform( + { + "organization_id": organization_id, + "invite_domains": invite_domains, + "name": name, + }, + organization_update_params.OrganizationUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrganizationUpdateResponse, + ) + + def delete( + self, + *, + organization_id: str, + # 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, + ) -> object: + """ + Permanently deletes an organization. + + Use this method to: + + - Remove unused organizations + - Clean up test organizations + - Complete organization migration + + ### Examples + + - Delete organization: + + Permanently removes an organization and all its data. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + organization_id: organization_id is the ID of the organization to delete + + 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.OrganizationService/DeleteOrganization", + body=maybe_transform( + {"organization_id": organization_id}, organization_delete_params.OrganizationDeleteParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def join( + self, + *, + invite_id: str | NotGiven = NOT_GIVEN, + organization_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> OrganizationJoinResponse: + """ + Allows users to join an organization through direct ID, invite link, or + domain-based auto-join. + + Use this method to: + + - Join an organization via direct ID or invite + - Join automatically based on email domain + - Accept organization invitations + + ### Examples + + - Join via organization ID: + + Joins an organization directly when you have the ID. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + - Join via invite: + + Accepts an organization invitation link. + + ```yaml + inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + invite_id: invite_id is the unique identifier of the invite to join the organization. + + organization_id: organization_id is the unique identifier of the Organization to join. + + 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.OrganizationService/JoinOrganization", + body=maybe_transform( + { + "invite_id": invite_id, + "organization_id": organization_id, + }, + organization_join_params.OrganizationJoinParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrganizationJoinResponse, + ) + + def leave( + self, + *, + user_id: str, + # 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, + ) -> object: + """ + Removes a user from an organization while preserving organization data. + + Use this method to: + + - Remove yourself from an organization + - Clean up inactive memberships + - Transfer project ownership before leaving + - Manage team transitions + + ### Examples + + - Leave organization: + + Removes user from organization membership. + + ```yaml + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + ``` + + Note: Ensure all projects and resources are transferred before leaving. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/LeaveOrganization", + body=maybe_transform({"user_id": user_id}, organization_leave_params.OrganizationLeaveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list_members( + self, + *, + organization_id: str, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: organization_list_members_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncMembersPage[OrganizationMember]: + """ + Lists and filters organization members with optional pagination. + + Use this method to: + + - View all organization members + - Monitor member activity + - Manage team membership + + ### Examples + + - List active members: + + Retrieves active members with pagination. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + - List with pagination: + + Retrieves next page of members. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 50 + token: "next-page-token-from-previous-response" + ``` + + Args: + organization_id: organization_id is the ID of the organization to list members for + + pagination: pagination contains the pagination options for listing members + + 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._get_api_list( + "/gitpod.v1.OrganizationService/ListMembers", + page=SyncMembersPage[OrganizationMember], + body=maybe_transform( + { + "organization_id": organization_id, + "pagination": pagination, + }, + organization_list_members_params.OrganizationListMembersParams, + ), + 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, + }, + organization_list_members_params.OrganizationListMembersParams, + ), + ), + model=OrganizationMember, + method="post", + ) + + def set_role( + self, + *, + organization_id: str, + user_id: str, + role: OrganizationRole | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Manages organization membership and roles by setting a user's role within the + organization. + + Use this method to: + + - Promote members to admin role + - Change member permissions + - Demote admins to regular members + + ### Examples + + - Promote to admin: + + Makes a user an organization administrator. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: ORGANIZATION_ROLE_ADMIN + ``` + + - Change to member: + + Changes a user's role to regular member. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: ORGANIZATION_ROLE_MEMBER + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/SetRole", + body=maybe_transform( + { + "organization_id": organization_id, + "user_id": user_id, + "role": role, + }, + organization_set_role_params.OrganizationSetRoleParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncOrganizationsResource(AsyncAPIResource): + @cached_property + def domain_verifications(self) -> AsyncDomainVerificationsResource: + return AsyncDomainVerificationsResource(self._client) + + @cached_property + def invites(self) -> AsyncInvitesResource: + return AsyncInvitesResource(self._client) + + @cached_property + def policies(self) -> AsyncPoliciesResource: + return AsyncPoliciesResource(self._client) + + @cached_property + def sso_configurations(self) -> AsyncSSOConfigurationsResource: + return AsyncSSOConfigurationsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncOrganizationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncOrganizationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOrganizationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncOrganizationsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + invite_accounts_with_matching_domain: bool | NotGiven = NOT_GIVEN, + join_organization: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> OrganizationCreateResponse: + """ + Creates a new organization with the specified name and settings. + + Use this method to: + + - Create a new organization for team collaboration + - Set up automatic domain-based invites for team members + - Join the organization immediately upon creation + + ### Examples + + - Create a basic organization: + + Creates an organization with just a name. + + ```yaml + name: "Acme Corp Engineering" + joinOrganization: true + ``` + + - Create with domain-based invites: + + Creates an organization that automatically invites users with matching email + domains. + + ```yaml + name: "Acme Corp" + joinOrganization: true + inviteAccountsWithMatchingDomain: true + ``` + + Args: + name: name is the organization name + + invite_accounts_with_matching_domain: Should other Accounts with the same domain be automatically invited to the + organization? + + join_organization: join_organization decides whether the Identity issuing this request joins the + org on creation + + 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.OrganizationService/CreateOrganization", + body=await async_maybe_transform( + { + "name": name, + "invite_accounts_with_matching_domain": invite_accounts_with_matching_domain, + "join_organization": join_organization, + }, + organization_create_params.OrganizationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrganizationCreateResponse, + ) + + async def retrieve( + self, + *, + organization_id: str, + # 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, + ) -> OrganizationRetrieveResponse: + """ + Gets details about a specific organization. + + Use this method to: + + - Retrieve organization settings and configuration + - Check organization membership status + - View domain verification settings + + ### Examples + + - Get organization details: + + Retrieves information about a specific organization. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + organization_id: organization_id is the unique identifier of the Organization to retreive. + + 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.OrganizationService/GetOrganization", + body=await async_maybe_transform( + {"organization_id": organization_id}, organization_retrieve_params.OrganizationRetrieveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrganizationRetrieveResponse, + ) + + async def update( + self, + *, + organization_id: str, + invite_domains: Optional[InviteDomainsParam] | NotGiven = NOT_GIVEN, + name: Optional[str] | NotGiven = NOT_GIVEN, + # 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, + ) -> OrganizationUpdateResponse: + """ + Updates an organization's settings including name, invite domains, and member + policies. + + Use this method to: + + - Modify organization display name + - Configure email domain restrictions + - Update organization-wide settings + - Manage member access policies + + ### Examples + + - Update basic settings: + + Changes organization name and invite domains. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + name: "New Company Name" + inviteDomains: + domains: + - "company.com" + - "subsidiary.com" + ``` + + - Remove domain restrictions: + + Clears all domain-based invite restrictions. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + inviteDomains: + domains: [] + ``` + + Args: + organization_id: organization_id is the ID of the organization to update the settings for. + + invite_domains: invite_domains is the domain allowlist of the organization + + name: name is the new name of the organization + + 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.OrganizationService/UpdateOrganization", + body=await async_maybe_transform( + { + "organization_id": organization_id, + "invite_domains": invite_domains, + "name": name, + }, + organization_update_params.OrganizationUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrganizationUpdateResponse, + ) + + async def delete( + self, + *, + organization_id: str, + # 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, + ) -> object: + """ + Permanently deletes an organization. + + Use this method to: + + - Remove unused organizations + - Clean up test organizations + - Complete organization migration + + ### Examples + + - Delete organization: + + Permanently removes an organization and all its data. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + organization_id: organization_id is the ID of the organization to delete + + 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.OrganizationService/DeleteOrganization", + body=await async_maybe_transform( + {"organization_id": organization_id}, organization_delete_params.OrganizationDeleteParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def join( + self, + *, + invite_id: str | NotGiven = NOT_GIVEN, + organization_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> OrganizationJoinResponse: + """ + Allows users to join an organization through direct ID, invite link, or + domain-based auto-join. + + Use this method to: + + - Join an organization via direct ID or invite + - Join automatically based on email domain + - Accept organization invitations + + ### Examples + + - Join via organization ID: + + Joins an organization directly when you have the ID. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + - Join via invite: + + Accepts an organization invitation link. + + ```yaml + inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + invite_id: invite_id is the unique identifier of the invite to join the organization. + + organization_id: organization_id is the unique identifier of the Organization to join. + + 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.OrganizationService/JoinOrganization", + body=await async_maybe_transform( + { + "invite_id": invite_id, + "organization_id": organization_id, + }, + organization_join_params.OrganizationJoinParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrganizationJoinResponse, + ) + + async def leave( + self, + *, + user_id: str, + # 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, + ) -> object: + """ + Removes a user from an organization while preserving organization data. + + Use this method to: + + - Remove yourself from an organization + - Clean up inactive memberships + - Transfer project ownership before leaving + - Manage team transitions + + ### Examples + + - Leave organization: + + Removes user from organization membership. + + ```yaml + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + ``` + + Note: Ensure all projects and resources are transferred before leaving. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/LeaveOrganization", + body=await async_maybe_transform({"user_id": user_id}, organization_leave_params.OrganizationLeaveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list_members( + self, + *, + organization_id: str, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: organization_list_members_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[OrganizationMember, AsyncMembersPage[OrganizationMember]]: + """ + Lists and filters organization members with optional pagination. + + Use this method to: + + - View all organization members + - Monitor member activity + - Manage team membership + + ### Examples + + - List active members: + + Retrieves active members with pagination. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + - List with pagination: + + Retrieves next page of members. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 50 + token: "next-page-token-from-previous-response" + ``` + + Args: + organization_id: organization_id is the ID of the organization to list members for + + pagination: pagination contains the pagination options for listing members + + 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._get_api_list( + "/gitpod.v1.OrganizationService/ListMembers", + page=AsyncMembersPage[OrganizationMember], + body=maybe_transform( + { + "organization_id": organization_id, + "pagination": pagination, + }, + organization_list_members_params.OrganizationListMembersParams, + ), + 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, + }, + organization_list_members_params.OrganizationListMembersParams, + ), + ), + model=OrganizationMember, + method="post", + ) + + async def set_role( + self, + *, + organization_id: str, + user_id: str, + role: OrganizationRole | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Manages organization membership and roles by setting a user's role within the + organization. + + Use this method to: + + - Promote members to admin role + - Change member permissions + - Demote admins to regular members + + ### Examples + + - Promote to admin: + + Makes a user an organization administrator. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: ORGANIZATION_ROLE_ADMIN + ``` + + - Change to member: + + Changes a user's role to regular member. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: ORGANIZATION_ROLE_MEMBER + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/SetRole", + body=await async_maybe_transform( + { + "organization_id": organization_id, + "user_id": user_id, + "role": role, + }, + organization_set_role_params.OrganizationSetRoleParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class OrganizationsResourceWithRawResponse: + def __init__(self, organizations: OrganizationsResource) -> None: + self._organizations = organizations + + self.create = to_raw_response_wrapper( + organizations.create, + ) + self.retrieve = to_raw_response_wrapper( + organizations.retrieve, + ) + self.update = to_raw_response_wrapper( + organizations.update, + ) + self.delete = to_raw_response_wrapper( + organizations.delete, + ) + self.join = to_raw_response_wrapper( + organizations.join, + ) + self.leave = to_raw_response_wrapper( + organizations.leave, + ) + self.list_members = to_raw_response_wrapper( + organizations.list_members, + ) + self.set_role = to_raw_response_wrapper( + organizations.set_role, + ) + + @cached_property + def domain_verifications(self) -> DomainVerificationsResourceWithRawResponse: + return DomainVerificationsResourceWithRawResponse(self._organizations.domain_verifications) + + @cached_property + def invites(self) -> InvitesResourceWithRawResponse: + return InvitesResourceWithRawResponse(self._organizations.invites) + + @cached_property + def policies(self) -> PoliciesResourceWithRawResponse: + return PoliciesResourceWithRawResponse(self._organizations.policies) + + @cached_property + def sso_configurations(self) -> SSOConfigurationsResourceWithRawResponse: + return SSOConfigurationsResourceWithRawResponse(self._organizations.sso_configurations) + + +class AsyncOrganizationsResourceWithRawResponse: + def __init__(self, organizations: AsyncOrganizationsResource) -> None: + self._organizations = organizations + + self.create = async_to_raw_response_wrapper( + organizations.create, + ) + self.retrieve = async_to_raw_response_wrapper( + organizations.retrieve, + ) + self.update = async_to_raw_response_wrapper( + organizations.update, + ) + self.delete = async_to_raw_response_wrapper( + organizations.delete, + ) + self.join = async_to_raw_response_wrapper( + organizations.join, + ) + self.leave = async_to_raw_response_wrapper( + organizations.leave, + ) + self.list_members = async_to_raw_response_wrapper( + organizations.list_members, + ) + self.set_role = async_to_raw_response_wrapper( + organizations.set_role, + ) + + @cached_property + def domain_verifications(self) -> AsyncDomainVerificationsResourceWithRawResponse: + return AsyncDomainVerificationsResourceWithRawResponse(self._organizations.domain_verifications) + + @cached_property + def invites(self) -> AsyncInvitesResourceWithRawResponse: + return AsyncInvitesResourceWithRawResponse(self._organizations.invites) + + @cached_property + def policies(self) -> AsyncPoliciesResourceWithRawResponse: + return AsyncPoliciesResourceWithRawResponse(self._organizations.policies) + + @cached_property + def sso_configurations(self) -> AsyncSSOConfigurationsResourceWithRawResponse: + return AsyncSSOConfigurationsResourceWithRawResponse(self._organizations.sso_configurations) + + +class OrganizationsResourceWithStreamingResponse: + def __init__(self, organizations: OrganizationsResource) -> None: + self._organizations = organizations + + self.create = to_streamed_response_wrapper( + organizations.create, + ) + self.retrieve = to_streamed_response_wrapper( + organizations.retrieve, + ) + self.update = to_streamed_response_wrapper( + organizations.update, + ) + self.delete = to_streamed_response_wrapper( + organizations.delete, + ) + self.join = to_streamed_response_wrapper( + organizations.join, + ) + self.leave = to_streamed_response_wrapper( + organizations.leave, + ) + self.list_members = to_streamed_response_wrapper( + organizations.list_members, + ) + self.set_role = to_streamed_response_wrapper( + organizations.set_role, + ) + + @cached_property + def domain_verifications(self) -> DomainVerificationsResourceWithStreamingResponse: + return DomainVerificationsResourceWithStreamingResponse(self._organizations.domain_verifications) + + @cached_property + def invites(self) -> InvitesResourceWithStreamingResponse: + return InvitesResourceWithStreamingResponse(self._organizations.invites) + + @cached_property + def policies(self) -> PoliciesResourceWithStreamingResponse: + return PoliciesResourceWithStreamingResponse(self._organizations.policies) + + @cached_property + def sso_configurations(self) -> SSOConfigurationsResourceWithStreamingResponse: + return SSOConfigurationsResourceWithStreamingResponse(self._organizations.sso_configurations) + + +class AsyncOrganizationsResourceWithStreamingResponse: + def __init__(self, organizations: AsyncOrganizationsResource) -> None: + self._organizations = organizations + + self.create = async_to_streamed_response_wrapper( + organizations.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + organizations.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + organizations.update, + ) + self.delete = async_to_streamed_response_wrapper( + organizations.delete, + ) + self.join = async_to_streamed_response_wrapper( + organizations.join, + ) + self.leave = async_to_streamed_response_wrapper( + organizations.leave, + ) + self.list_members = async_to_streamed_response_wrapper( + organizations.list_members, + ) + self.set_role = async_to_streamed_response_wrapper( + organizations.set_role, + ) + + @cached_property + def domain_verifications(self) -> AsyncDomainVerificationsResourceWithStreamingResponse: + return AsyncDomainVerificationsResourceWithStreamingResponse(self._organizations.domain_verifications) + + @cached_property + def invites(self) -> AsyncInvitesResourceWithStreamingResponse: + return AsyncInvitesResourceWithStreamingResponse(self._organizations.invites) + + @cached_property + def policies(self) -> AsyncPoliciesResourceWithStreamingResponse: + return AsyncPoliciesResourceWithStreamingResponse(self._organizations.policies) + + @cached_property + def sso_configurations(self) -> AsyncSSOConfigurationsResourceWithStreamingResponse: + return AsyncSSOConfigurationsResourceWithStreamingResponse(self._organizations.sso_configurations) diff --git a/src/gitpod/resources/organizations/policies.py b/src/gitpod/resources/organizations/policies.py new file mode 100644 index 0000000..feb894c --- /dev/null +++ b/src/gitpod/resources/organizations/policies.py @@ -0,0 +1,457 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.organizations import policy_update_params, policy_retrieve_params +from ...types.organizations.policy_retrieve_response import PolicyRetrieveResponse + +__all__ = ["PoliciesResource", "AsyncPoliciesResource"] + + +class PoliciesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return PoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return PoliciesResourceWithStreamingResponse(self) + + def retrieve( + self, + *, + organization_id: str, + # 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, + ) -> PolicyRetrieveResponse: + """ + Gets organization policy settings by organization ID. + + Use this method to: + + - Retrieve current policy settings for an organization + - View resource limits and restrictions + - Check allowed editors and other configurations + + ### Examples + + - Get organization policies: + + Retrieves policy settings for a specific organization. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + organization_id: organization_id is the ID of the organization to retrieve policies 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.OrganizationService/GetOrganizationPolicies", + body=maybe_transform({"organization_id": organization_id}, policy_retrieve_params.PolicyRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyRetrieveResponse, + ) + + def update( + self, + *, + organization_id: str, + allowed_editor_ids: List[str] | NotGiven = NOT_GIVEN, + allow_local_runners: Optional[bool] | NotGiven = NOT_GIVEN, + default_editor_id: Optional[str] | NotGiven = NOT_GIVEN, + default_environment_image: Optional[str] | NotGiven = NOT_GIVEN, + maximum_environments_per_user: Optional[str] | NotGiven = NOT_GIVEN, + maximum_environment_timeout: Optional[str] | NotGiven = NOT_GIVEN, + maximum_running_environments_per_user: Optional[str] | NotGiven = NOT_GIVEN, + members_create_projects: Optional[bool] | NotGiven = NOT_GIVEN, + members_require_projects: Optional[bool] | NotGiven = NOT_GIVEN, + port_sharing_disabled: Optional[bool] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates organization policy settings. + + Use this method to: + + - Configure editor restrictions + - Set environment resource limits + - Define project creation permissions + - Customize default configurations + + ### Examples + + - Update editor policies: + + Restricts available editors and sets a default. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + allowedEditorIds: + - "vscode" + - "jetbrains" + defaultEditorId: "vscode" + ``` + + - Set environment limits: + + Configures limits for environment usage. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + maximumEnvironmentTimeout: "3600s" + maximumRunningEnvironmentsPerUser: "5" + maximumEnvironmentsPerUser: "20" + ``` + + Args: + organization_id: organization_id is the ID of the organization to update policies for + + allowed_editor_ids: allowed_editor_ids is the list of editor IDs that are allowed to be used in the + organization + + allow_local_runners: allow_local_runners controls whether local runners are allowed to be used in the + organization + + default_editor_id: default_editor_id is the default editor ID to be used when a user doesn't + specify one + + default_environment_image: default_environment_image is the default container image when none is defined in + repo + + maximum_environments_per_user: maximum_environments_per_user limits total environments (running or stopped) per + user + + maximum_environment_timeout: maximum_environment_timeout controls the maximum timeout allowed for + environments in seconds. 0 means no limit (never). Minimum duration is 30 + minutes. + + maximum_running_environments_per_user: maximum_running_environments_per_user limits simultaneously running environments + per user + + members_create_projects: members_create_projects controls whether members can create projects + + members_require_projects: members_require_projects controls whether environments can only be created from + projects by non-admin users + + port_sharing_disabled: port_sharing_disabled controls whether port sharing is disabled in the + organization + + 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.OrganizationService/UpdateOrganizationPolicies", + body=maybe_transform( + { + "organization_id": organization_id, + "allowed_editor_ids": allowed_editor_ids, + "allow_local_runners": allow_local_runners, + "default_editor_id": default_editor_id, + "default_environment_image": default_environment_image, + "maximum_environments_per_user": maximum_environments_per_user, + "maximum_environment_timeout": maximum_environment_timeout, + "maximum_running_environments_per_user": maximum_running_environments_per_user, + "members_create_projects": members_create_projects, + "members_require_projects": members_require_projects, + "port_sharing_disabled": port_sharing_disabled, + }, + policy_update_params.PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncPoliciesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncPoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncPoliciesResourceWithStreamingResponse(self) + + async def retrieve( + self, + *, + organization_id: str, + # 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, + ) -> PolicyRetrieveResponse: + """ + Gets organization policy settings by organization ID. + + Use this method to: + + - Retrieve current policy settings for an organization + - View resource limits and restrictions + - Check allowed editors and other configurations + + ### Examples + + - Get organization policies: + + Retrieves policy settings for a specific organization. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + organization_id: organization_id is the ID of the organization to retrieve policies 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.OrganizationService/GetOrganizationPolicies", + body=await async_maybe_transform( + {"organization_id": organization_id}, policy_retrieve_params.PolicyRetrieveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyRetrieveResponse, + ) + + async def update( + self, + *, + organization_id: str, + allowed_editor_ids: List[str] | NotGiven = NOT_GIVEN, + allow_local_runners: Optional[bool] | NotGiven = NOT_GIVEN, + default_editor_id: Optional[str] | NotGiven = NOT_GIVEN, + default_environment_image: Optional[str] | NotGiven = NOT_GIVEN, + maximum_environments_per_user: Optional[str] | NotGiven = NOT_GIVEN, + maximum_environment_timeout: Optional[str] | NotGiven = NOT_GIVEN, + maximum_running_environments_per_user: Optional[str] | NotGiven = NOT_GIVEN, + members_create_projects: Optional[bool] | NotGiven = NOT_GIVEN, + members_require_projects: Optional[bool] | NotGiven = NOT_GIVEN, + port_sharing_disabled: Optional[bool] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates organization policy settings. + + Use this method to: + + - Configure editor restrictions + - Set environment resource limits + - Define project creation permissions + - Customize default configurations + + ### Examples + + - Update editor policies: + + Restricts available editors and sets a default. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + allowedEditorIds: + - "vscode" + - "jetbrains" + defaultEditorId: "vscode" + ``` + + - Set environment limits: + + Configures limits for environment usage. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + maximumEnvironmentTimeout: "3600s" + maximumRunningEnvironmentsPerUser: "5" + maximumEnvironmentsPerUser: "20" + ``` + + Args: + organization_id: organization_id is the ID of the organization to update policies for + + allowed_editor_ids: allowed_editor_ids is the list of editor IDs that are allowed to be used in the + organization + + allow_local_runners: allow_local_runners controls whether local runners are allowed to be used in the + organization + + default_editor_id: default_editor_id is the default editor ID to be used when a user doesn't + specify one + + default_environment_image: default_environment_image is the default container image when none is defined in + repo + + maximum_environments_per_user: maximum_environments_per_user limits total environments (running or stopped) per + user + + maximum_environment_timeout: maximum_environment_timeout controls the maximum timeout allowed for + environments in seconds. 0 means no limit (never). Minimum duration is 30 + minutes. + + maximum_running_environments_per_user: maximum_running_environments_per_user limits simultaneously running environments + per user + + members_create_projects: members_create_projects controls whether members can create projects + + members_require_projects: members_require_projects controls whether environments can only be created from + projects by non-admin users + + port_sharing_disabled: port_sharing_disabled controls whether port sharing is disabled in the + organization + + 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.OrganizationService/UpdateOrganizationPolicies", + body=await async_maybe_transform( + { + "organization_id": organization_id, + "allowed_editor_ids": allowed_editor_ids, + "allow_local_runners": allow_local_runners, + "default_editor_id": default_editor_id, + "default_environment_image": default_environment_image, + "maximum_environments_per_user": maximum_environments_per_user, + "maximum_environment_timeout": maximum_environment_timeout, + "maximum_running_environments_per_user": maximum_running_environments_per_user, + "members_create_projects": members_create_projects, + "members_require_projects": members_require_projects, + "port_sharing_disabled": port_sharing_disabled, + }, + policy_update_params.PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class PoliciesResourceWithRawResponse: + def __init__(self, policies: PoliciesResource) -> None: + self._policies = policies + + self.retrieve = to_raw_response_wrapper( + policies.retrieve, + ) + self.update = to_raw_response_wrapper( + policies.update, + ) + + +class AsyncPoliciesResourceWithRawResponse: + def __init__(self, policies: AsyncPoliciesResource) -> None: + self._policies = policies + + self.retrieve = async_to_raw_response_wrapper( + policies.retrieve, + ) + self.update = async_to_raw_response_wrapper( + policies.update, + ) + + +class PoliciesResourceWithStreamingResponse: + def __init__(self, policies: PoliciesResource) -> None: + self._policies = policies + + self.retrieve = to_streamed_response_wrapper( + policies.retrieve, + ) + self.update = to_streamed_response_wrapper( + policies.update, + ) + + +class AsyncPoliciesResourceWithStreamingResponse: + def __init__(self, policies: AsyncPoliciesResource) -> None: + self._policies = policies + + self.retrieve = async_to_streamed_response_wrapper( + policies.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + policies.update, + ) diff --git a/src/gitpod/resources/organizations/sso_configurations.py b/src/gitpod/resources/organizations/sso_configurations.py new file mode 100644 index 0000000..6cdb528 --- /dev/null +++ b/src/gitpod/resources/organizations/sso_configurations.py @@ -0,0 +1,890 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncSSOConfigurationsPage, AsyncSSOConfigurationsPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.organizations import ( + SSOConfigurationState, + sso_configuration_list_params, + sso_configuration_create_params, + sso_configuration_delete_params, + sso_configuration_update_params, + sso_configuration_retrieve_params, +) +from ...types.organizations.sso_configuration import SSOConfiguration +from ...types.organizations.sso_configuration_state import SSOConfigurationState +from ...types.organizations.sso_configuration_create_response import SSOConfigurationCreateResponse +from ...types.organizations.sso_configuration_retrieve_response import SSOConfigurationRetrieveResponse + +__all__ = ["SSOConfigurationsResource", "AsyncSSOConfigurationsResource"] + + +class SSOConfigurationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SSOConfigurationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return SSOConfigurationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SSOConfigurationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return SSOConfigurationsResourceWithStreamingResponse(self) + + def create( + self, + *, + client_id: str, + client_secret: str, + email_domain: str, + issuer_url: str, + organization_id: str, + # 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, + ) -> SSOConfigurationCreateResponse: + """ + Creates or updates SSO configuration for organizational authentication. + + Use this method to: + + - Configure OIDC-based SSO providers + - Set up built-in providers (Google, GitHub, etc.) + - Define custom identity providers + - Manage authentication policies + + ### Examples + + - Configure built-in Google SSO: + + Sets up SSO using Google Workspace. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + clientId: "012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com" + clientSecret: "GOCSPX-abcdefghijklmnopqrstuvwxyz123456" + issuerUrl: "https://accounts.google.com" + emailDomain: "acme-corp.com" + ``` + + - Configure custom OIDC provider: + + Sets up SSO with a custom identity provider. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + clientId: "acme-corp-gitpod" + clientSecret: "secret-token-value" + issuerUrl: "https://sso.acme-corp.com" + emailDomain: "acme-corp.com" + ``` + + Args: + client_id: client_id is the client ID of the OIDC application set on the IdP + + client_secret: client_secret is the client secret of the OIDC application set on the IdP + + email_domain: email_domain is the domain that is allowed to sign in to the organization + + issuer_url: issuer_url is the URL of the IdP issuer + + 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.OrganizationService/CreateSSOConfiguration", + body=maybe_transform( + { + "client_id": client_id, + "client_secret": client_secret, + "email_domain": email_domain, + "issuer_url": issuer_url, + "organization_id": organization_id, + }, + sso_configuration_create_params.SSOConfigurationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSOConfigurationCreateResponse, + ) + + def retrieve( + self, + *, + sso_configuration_id: str, + # 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, + ) -> SSOConfigurationRetrieveResponse: + """ + Retrieves a specific SSO configuration. + + Use this method to: + + - View SSO provider details + - Check configuration status + - Verify SSO settings + + ### Examples + + - Get SSO configuration: + + Retrieves details of a specific SSO configuration. + + ```yaml + ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + sso_configuration_id: sso_configuration_id is the ID of the SSO configuration to get + + 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.OrganizationService/GetSSOConfiguration", + body=maybe_transform( + {"sso_configuration_id": sso_configuration_id}, + sso_configuration_retrieve_params.SSOConfigurationRetrieveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSOConfigurationRetrieveResponse, + ) + + def update( + self, + *, + sso_configuration_id: str, + claims: Dict[str, str] | NotGiven = NOT_GIVEN, + client_id: Optional[str] | NotGiven = NOT_GIVEN, + client_secret: Optional[str] | NotGiven = NOT_GIVEN, + email_domain: Optional[str] | NotGiven = NOT_GIVEN, + issuer_url: Optional[str] | NotGiven = NOT_GIVEN, + state: Optional[SSOConfigurationState] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates SSO provider settings and authentication rules. + + Use this method to: + + - Rotate client credentials + - Update provider endpoints + - Modify claim mappings + - Change authentication policies + - Toggle SSO enforcement + + ### Examples + + - Update credentials: + + Rotates client ID and secret. + + ```yaml + ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + clientId: "new-client-id" + clientSecret: "new-client-secret" + ``` + + - Update provider status: + + Activates or deactivates SSO provider. + + ```yaml + ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + state: SSO_CONFIGURATION_STATE_ACTIVE + ``` + + Args: + sso_configuration_id: sso_configuration_id is the ID of the SSO configuration to update + + claims: claims are key/value pairs that defines a mapping of claims issued by the IdP. + + client_id: client_id is the client ID of the SSO provider + + client_secret: client_secret is the client secret of the SSO provider + + issuer_url: issuer_url is the URL of the IdP issuer + + state: state is the state of the SSO configuration + + 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.OrganizationService/UpdateSSOConfiguration", + body=maybe_transform( + { + "sso_configuration_id": sso_configuration_id, + "claims": claims, + "client_id": client_id, + "client_secret": client_secret, + "email_domain": email_domain, + "issuer_url": issuer_url, + "state": state, + }, + sso_configuration_update_params.SSOConfigurationUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + organization_id: str, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: sso_configuration_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncSSOConfigurationsPage[SSOConfiguration]: + """ + Lists and filters SSO configurations for an organization. + + Use this method to: + + - View all SSO providers + - Monitor authentication status + - Audit security settings + - Manage provider configurations + + ### Examples + + - List active configurations: + + Shows all active SSO providers. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + - List by provider type: + + Shows custom SSO configurations. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + token: "next-page-token-from-previous-response" + ``` + + Args: + organization_id: organization_id is the ID of the organization to list SSO configurations 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._get_api_list( + "/gitpod.v1.OrganizationService/ListSSOConfigurations", + page=SyncSSOConfigurationsPage[SSOConfiguration], + body=maybe_transform( + { + "organization_id": organization_id, + "pagination": pagination, + }, + sso_configuration_list_params.SSOConfigurationListParams, + ), + 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, + }, + sso_configuration_list_params.SSOConfigurationListParams, + ), + ), + model=SSOConfiguration, + method="post", + ) + + def delete( + self, + *, + sso_configuration_id: str, + # 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, + ) -> object: + """ + Removes an SSO configuration from an organization. + + Use this method to: + + - Disable SSO authentication + - Remove outdated providers + - Clean up unused configurations + + ### Examples + + - Delete SSO configuration: + + Removes a specific SSO configuration. + + ```yaml + ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.OrganizationService/DeleteSSOConfiguration", + body=maybe_transform( + {"sso_configuration_id": sso_configuration_id}, + sso_configuration_delete_params.SSOConfigurationDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncSSOConfigurationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSSOConfigurationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncSSOConfigurationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSSOConfigurationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncSSOConfigurationsResourceWithStreamingResponse(self) + + async def create( + self, + *, + client_id: str, + client_secret: str, + email_domain: str, + issuer_url: str, + organization_id: str, + # 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, + ) -> SSOConfigurationCreateResponse: + """ + Creates or updates SSO configuration for organizational authentication. + + Use this method to: + + - Configure OIDC-based SSO providers + - Set up built-in providers (Google, GitHub, etc.) + - Define custom identity providers + - Manage authentication policies + + ### Examples + + - Configure built-in Google SSO: + + Sets up SSO using Google Workspace. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + clientId: "012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com" + clientSecret: "GOCSPX-abcdefghijklmnopqrstuvwxyz123456" + issuerUrl: "https://accounts.google.com" + emailDomain: "acme-corp.com" + ``` + + - Configure custom OIDC provider: + + Sets up SSO with a custom identity provider. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + clientId: "acme-corp-gitpod" + clientSecret: "secret-token-value" + issuerUrl: "https://sso.acme-corp.com" + emailDomain: "acme-corp.com" + ``` + + Args: + client_id: client_id is the client ID of the OIDC application set on the IdP + + client_secret: client_secret is the client secret of the OIDC application set on the IdP + + email_domain: email_domain is the domain that is allowed to sign in to the organization + + issuer_url: issuer_url is the URL of the IdP issuer + + 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.OrganizationService/CreateSSOConfiguration", + body=await async_maybe_transform( + { + "client_id": client_id, + "client_secret": client_secret, + "email_domain": email_domain, + "issuer_url": issuer_url, + "organization_id": organization_id, + }, + sso_configuration_create_params.SSOConfigurationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSOConfigurationCreateResponse, + ) + + async def retrieve( + self, + *, + sso_configuration_id: str, + # 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, + ) -> SSOConfigurationRetrieveResponse: + """ + Retrieves a specific SSO configuration. + + Use this method to: + + - View SSO provider details + - Check configuration status + - Verify SSO settings + + ### Examples + + - Get SSO configuration: + + Retrieves details of a specific SSO configuration. + + ```yaml + ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + sso_configuration_id: sso_configuration_id is the ID of the SSO configuration to get + + 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.OrganizationService/GetSSOConfiguration", + body=await async_maybe_transform( + {"sso_configuration_id": sso_configuration_id}, + sso_configuration_retrieve_params.SSOConfigurationRetrieveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSOConfigurationRetrieveResponse, + ) + + async def update( + self, + *, + sso_configuration_id: str, + claims: Dict[str, str] | NotGiven = NOT_GIVEN, + client_id: Optional[str] | NotGiven = NOT_GIVEN, + client_secret: Optional[str] | NotGiven = NOT_GIVEN, + email_domain: Optional[str] | NotGiven = NOT_GIVEN, + issuer_url: Optional[str] | NotGiven = NOT_GIVEN, + state: Optional[SSOConfigurationState] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates SSO provider settings and authentication rules. + + Use this method to: + + - Rotate client credentials + - Update provider endpoints + - Modify claim mappings + - Change authentication policies + - Toggle SSO enforcement + + ### Examples + + - Update credentials: + + Rotates client ID and secret. + + ```yaml + ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + clientId: "new-client-id" + clientSecret: "new-client-secret" + ``` + + - Update provider status: + + Activates or deactivates SSO provider. + + ```yaml + ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + state: SSO_CONFIGURATION_STATE_ACTIVE + ``` + + Args: + sso_configuration_id: sso_configuration_id is the ID of the SSO configuration to update + + claims: claims are key/value pairs that defines a mapping of claims issued by the IdP. + + client_id: client_id is the client ID of the SSO provider + + client_secret: client_secret is the client secret of the SSO provider + + issuer_url: issuer_url is the URL of the IdP issuer + + state: state is the state of the SSO configuration + + 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.OrganizationService/UpdateSSOConfiguration", + body=await async_maybe_transform( + { + "sso_configuration_id": sso_configuration_id, + "claims": claims, + "client_id": client_id, + "client_secret": client_secret, + "email_domain": email_domain, + "issuer_url": issuer_url, + "state": state, + }, + sso_configuration_update_params.SSOConfigurationUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + organization_id: str, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: sso_configuration_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[SSOConfiguration, AsyncSSOConfigurationsPage[SSOConfiguration]]: + """ + Lists and filters SSO configurations for an organization. + + Use this method to: + + - View all SSO providers + - Monitor authentication status + - Audit security settings + - Manage provider configurations + + ### Examples + + - List active configurations: + + Shows all active SSO providers. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + - List by provider type: + + Shows custom SSO configurations. + + ```yaml + organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + token: "next-page-token-from-previous-response" + ``` + + Args: + organization_id: organization_id is the ID of the organization to list SSO configurations 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._get_api_list( + "/gitpod.v1.OrganizationService/ListSSOConfigurations", + page=AsyncSSOConfigurationsPage[SSOConfiguration], + body=maybe_transform( + { + "organization_id": organization_id, + "pagination": pagination, + }, + sso_configuration_list_params.SSOConfigurationListParams, + ), + 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, + }, + sso_configuration_list_params.SSOConfigurationListParams, + ), + ), + model=SSOConfiguration, + method="post", + ) + + async def delete( + self, + *, + sso_configuration_id: str, + # 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, + ) -> object: + """ + Removes an SSO configuration from an organization. + + Use this method to: + + - Disable SSO authentication + - Remove outdated providers + - Clean up unused configurations + + ### Examples + + - Delete SSO configuration: + + Removes a specific SSO configuration. + + ```yaml + ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.OrganizationService/DeleteSSOConfiguration", + body=await async_maybe_transform( + {"sso_configuration_id": sso_configuration_id}, + sso_configuration_delete_params.SSOConfigurationDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class SSOConfigurationsResourceWithRawResponse: + def __init__(self, sso_configurations: SSOConfigurationsResource) -> None: + self._sso_configurations = sso_configurations + + self.create = to_raw_response_wrapper( + sso_configurations.create, + ) + self.retrieve = to_raw_response_wrapper( + sso_configurations.retrieve, + ) + self.update = to_raw_response_wrapper( + sso_configurations.update, + ) + self.list = to_raw_response_wrapper( + sso_configurations.list, + ) + self.delete = to_raw_response_wrapper( + sso_configurations.delete, + ) + + +class AsyncSSOConfigurationsResourceWithRawResponse: + def __init__(self, sso_configurations: AsyncSSOConfigurationsResource) -> None: + self._sso_configurations = sso_configurations + + self.create = async_to_raw_response_wrapper( + sso_configurations.create, + ) + self.retrieve = async_to_raw_response_wrapper( + sso_configurations.retrieve, + ) + self.update = async_to_raw_response_wrapper( + sso_configurations.update, + ) + self.list = async_to_raw_response_wrapper( + sso_configurations.list, + ) + self.delete = async_to_raw_response_wrapper( + sso_configurations.delete, + ) + + +class SSOConfigurationsResourceWithStreamingResponse: + def __init__(self, sso_configurations: SSOConfigurationsResource) -> None: + self._sso_configurations = sso_configurations + + self.create = to_streamed_response_wrapper( + sso_configurations.create, + ) + self.retrieve = to_streamed_response_wrapper( + sso_configurations.retrieve, + ) + self.update = to_streamed_response_wrapper( + sso_configurations.update, + ) + self.list = to_streamed_response_wrapper( + sso_configurations.list, + ) + self.delete = to_streamed_response_wrapper( + sso_configurations.delete, + ) + + +class AsyncSSOConfigurationsResourceWithStreamingResponse: + def __init__(self, sso_configurations: AsyncSSOConfigurationsResource) -> None: + self._sso_configurations = sso_configurations + + self.create = async_to_streamed_response_wrapper( + sso_configurations.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + sso_configurations.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + sso_configurations.update, + ) + self.list = async_to_streamed_response_wrapper( + sso_configurations.list, + ) + self.delete = async_to_streamed_response_wrapper( + sso_configurations.delete, + ) diff --git a/src/gitpod/resources/projects/__init__.py b/src/gitpod/resources/projects/__init__.py new file mode 100644 index 0000000..da8b964 --- /dev/null +++ b/src/gitpod/resources/projects/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .policies import ( + PoliciesResource, + AsyncPoliciesResource, + PoliciesResourceWithRawResponse, + AsyncPoliciesResourceWithRawResponse, + PoliciesResourceWithStreamingResponse, + AsyncPoliciesResourceWithStreamingResponse, +) +from .projects import ( + ProjectsResource, + AsyncProjectsResource, + ProjectsResourceWithRawResponse, + AsyncProjectsResourceWithRawResponse, + ProjectsResourceWithStreamingResponse, + AsyncProjectsResourceWithStreamingResponse, +) + +__all__ = [ + "PoliciesResource", + "AsyncPoliciesResource", + "PoliciesResourceWithRawResponse", + "AsyncPoliciesResourceWithRawResponse", + "PoliciesResourceWithStreamingResponse", + "AsyncPoliciesResourceWithStreamingResponse", + "ProjectsResource", + "AsyncProjectsResource", + "ProjectsResourceWithRawResponse", + "AsyncProjectsResourceWithRawResponse", + "ProjectsResourceWithStreamingResponse", + "AsyncProjectsResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/projects/policies.py b/src/gitpod/resources/projects/policies.py new file mode 100644 index 0000000..fc12621 --- /dev/null +++ b/src/gitpod/resources/projects/policies.py @@ -0,0 +1,667 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncPoliciesPage, AsyncPoliciesPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.projects import ( + ProjectRole, + policy_list_params, + policy_create_params, + policy_delete_params, + policy_update_params, +) +from ...types.projects.project_role import ProjectRole +from ...types.projects.project_policy import ProjectPolicy +from ...types.projects.policy_create_response import PolicyCreateResponse +from ...types.projects.policy_update_response import PolicyUpdateResponse + +__all__ = ["PoliciesResource", "AsyncPoliciesResource"] + + +class PoliciesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return PoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return PoliciesResourceWithStreamingResponse(self) + + def create( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + role: ProjectRole | NotGiven = NOT_GIVEN, + # 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, + ) -> PolicyCreateResponse: + """ + Creates a new policy for a project. + + Use this method to: + + - Set up access controls + - Define group permissions + - Configure role-based access + + ### Examples + + - Create admin policy: + + Grants admin access to a group. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: PROJECT_ROLE_ADMIN + ``` + + Args: + group_id: group_id specifies the group_id identifier + + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.ProjectService/CreateProjectPolicy", + body=maybe_transform( + { + "group_id": group_id, + "project_id": project_id, + "role": role, + }, + policy_create_params.PolicyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyCreateResponse, + ) + + def update( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + role: ProjectRole | NotGiven = NOT_GIVEN, + # 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, + ) -> PolicyUpdateResponse: + """ + Updates an existing project policy. + + Use this method to: + + - Modify access levels + - Change group roles + - Update permissions + + ### Examples + + - Update policy role: + + Changes a group's access level. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: PROJECT_ROLE_EDITOR + ``` + + Args: + group_id: group_id specifies the group_id identifier + + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.ProjectService/UpdateProjectPolicy", + body=maybe_transform( + { + "group_id": group_id, + "project_id": project_id, + "role": role, + }, + policy_update_params.PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyUpdateResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: policy_list_params.Pagination | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncPoliciesPage[ProjectPolicy]: + """ + Lists policies for a project. + + Use this method to: + + - View access controls + - Check policy configurations + - Audit permissions + + ### Examples + + - List policies: + + Shows all policies for a project. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing project policies + + project_id: project_id specifies the project identifier + + 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._get_api_list( + "/gitpod.v1.ProjectService/ListProjectPolicies", + page=SyncPoliciesPage[ProjectPolicy], + body=maybe_transform( + { + "pagination": pagination, + "project_id": project_id, + }, + policy_list_params.PolicyListParams, + ), + 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, + }, + policy_list_params.PolicyListParams, + ), + ), + model=ProjectPolicy, + method="post", + ) + + def delete( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a project policy. + + Use this method to: + + - Remove access controls + - Revoke permissions + - Clean up policies + + ### Examples + + - Delete policy: + + Removes a group's access policy. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + ``` + + Args: + group_id: group_id specifies the group_id identifier + + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.ProjectService/DeleteProjectPolicy", + body=maybe_transform( + { + "group_id": group_id, + "project_id": project_id, + }, + policy_delete_params.PolicyDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncPoliciesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncPoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncPoliciesResourceWithStreamingResponse(self) + + async def create( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + role: ProjectRole | NotGiven = NOT_GIVEN, + # 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, + ) -> PolicyCreateResponse: + """ + Creates a new policy for a project. + + Use this method to: + + - Set up access controls + - Define group permissions + - Configure role-based access + + ### Examples + + - Create admin policy: + + Grants admin access to a group. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: PROJECT_ROLE_ADMIN + ``` + + Args: + group_id: group_id specifies the group_id identifier + + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.ProjectService/CreateProjectPolicy", + body=await async_maybe_transform( + { + "group_id": group_id, + "project_id": project_id, + "role": role, + }, + policy_create_params.PolicyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyCreateResponse, + ) + + async def update( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + role: ProjectRole | NotGiven = NOT_GIVEN, + # 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, + ) -> PolicyUpdateResponse: + """ + Updates an existing project policy. + + Use this method to: + + - Modify access levels + - Change group roles + - Update permissions + + ### Examples + + - Update policy role: + + Changes a group's access level. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: PROJECT_ROLE_EDITOR + ``` + + Args: + group_id: group_id specifies the group_id identifier + + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.ProjectService/UpdateProjectPolicy", + body=await async_maybe_transform( + { + "group_id": group_id, + "project_id": project_id, + "role": role, + }, + policy_update_params.PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyUpdateResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: policy_list_params.Pagination | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[ProjectPolicy, AsyncPoliciesPage[ProjectPolicy]]: + """ + Lists policies for a project. + + Use this method to: + + - View access controls + - Check policy configurations + - Audit permissions + + ### Examples + + - List policies: + + Shows all policies for a project. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing project policies + + project_id: project_id specifies the project identifier + + 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._get_api_list( + "/gitpod.v1.ProjectService/ListProjectPolicies", + page=AsyncPoliciesPage[ProjectPolicy], + body=maybe_transform( + { + "pagination": pagination, + "project_id": project_id, + }, + policy_list_params.PolicyListParams, + ), + 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, + }, + policy_list_params.PolicyListParams, + ), + ), + model=ProjectPolicy, + method="post", + ) + + async def delete( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a project policy. + + Use this method to: + + - Remove access controls + - Revoke permissions + - Clean up policies + + ### Examples + + - Delete policy: + + Removes a group's access policy. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + ``` + + Args: + group_id: group_id specifies the group_id identifier + + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.ProjectService/DeleteProjectPolicy", + body=await async_maybe_transform( + { + "group_id": group_id, + "project_id": project_id, + }, + policy_delete_params.PolicyDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class PoliciesResourceWithRawResponse: + def __init__(self, policies: PoliciesResource) -> None: + self._policies = policies + + self.create = to_raw_response_wrapper( + policies.create, + ) + self.update = to_raw_response_wrapper( + policies.update, + ) + self.list = to_raw_response_wrapper( + policies.list, + ) + self.delete = to_raw_response_wrapper( + policies.delete, + ) + + +class AsyncPoliciesResourceWithRawResponse: + def __init__(self, policies: AsyncPoliciesResource) -> None: + self._policies = policies + + self.create = async_to_raw_response_wrapper( + policies.create, + ) + self.update = async_to_raw_response_wrapper( + policies.update, + ) + self.list = async_to_raw_response_wrapper( + policies.list, + ) + self.delete = async_to_raw_response_wrapper( + policies.delete, + ) + + +class PoliciesResourceWithStreamingResponse: + def __init__(self, policies: PoliciesResource) -> None: + self._policies = policies + + self.create = to_streamed_response_wrapper( + policies.create, + ) + self.update = to_streamed_response_wrapper( + policies.update, + ) + self.list = to_streamed_response_wrapper( + policies.list, + ) + self.delete = to_streamed_response_wrapper( + policies.delete, + ) + + +class AsyncPoliciesResourceWithStreamingResponse: + def __init__(self, policies: AsyncPoliciesResource) -> None: + self._policies = policies + + self.create = async_to_streamed_response_wrapper( + policies.create, + ) + self.update = async_to_streamed_response_wrapper( + policies.update, + ) + self.list = async_to_streamed_response_wrapper( + policies.list, + ) + self.delete = async_to_streamed_response_wrapper( + policies.delete, + ) diff --git a/src/gitpod/resources/projects/projects.py b/src/gitpod/resources/projects/projects.py new file mode 100644 index 0000000..2c8e637 --- /dev/null +++ b/src/gitpod/resources/projects/projects.py @@ -0,0 +1,1073 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ...types import ( + project_list_params, + project_create_params, + project_delete_params, + project_update_params, + project_retrieve_params, + project_create_from_environment_params, +) +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from .policies import ( + PoliciesResource, + AsyncPoliciesResource, + PoliciesResourceWithRawResponse, + AsyncPoliciesResourceWithRawResponse, + PoliciesResourceWithStreamingResponse, + AsyncPoliciesResourceWithStreamingResponse, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncProjectsPage, AsyncProjectsPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.project import Project +from ...types.project_create_response import ProjectCreateResponse +from ...types.project_update_response import ProjectUpdateResponse +from ...types.project_retrieve_response import ProjectRetrieveResponse +from ...types.environment_initializer_param import EnvironmentInitializerParam +from ...types.project_environment_class_param import ProjectEnvironmentClassParam +from ...types.project_create_from_environment_response import ProjectCreateFromEnvironmentResponse + +__all__ = ["ProjectsResource", "AsyncProjectsResource"] + + +class ProjectsResource(SyncAPIResource): + @cached_property + def policies(self) -> PoliciesResource: + return PoliciesResource(self._client) + + @cached_property + def with_raw_response(self) -> ProjectsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return ProjectsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ProjectsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return ProjectsResourceWithStreamingResponse(self) + + def create( + self, + *, + environment_class: ProjectEnvironmentClassParam, + initializer: EnvironmentInitializerParam, + automations_file_path: str | NotGiven = NOT_GIVEN, + devcontainer_file_path: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + technical_description: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ProjectCreateResponse: + """ + Creates a new project with specified configuration. + + Use this method to: + + - Set up development projects + - Configure project environments + - Define project settings + - Initialize project content + + ### Examples + + - Create basic project: + + Creates a project with minimal configuration. + + ```yaml + name: "Web Application" + environmentClass: + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + initializer: + specs: + - git: + remoteUri: "https://github.com/org/repo" + ``` + + - Create project with devcontainer: + + Creates a project with custom development container. + + ```yaml + name: "Backend Service" + environmentClass: + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + initializer: + specs: + - git: + remoteUri: "https://github.com/org/backend" + devcontainerFilePath: ".devcontainer/devcontainer.json" + automationsFilePath: ".gitpod/automations.yaml" + ``` + + Args: + initializer: initializer is the content initializer + + automations_file_path: automations_file_path is the path to the automations file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches("^$|^[^/].*") + ``` + + devcontainer_file_path: devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches("^$|^[^/].*") + ``` + + 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 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.ProjectService/CreateProject", + body=maybe_transform( + { + "environment_class": environment_class, + "initializer": initializer, + "automations_file_path": automations_file_path, + "devcontainer_file_path": devcontainer_file_path, + "name": name, + "technical_description": technical_description, + }, + project_create_params.ProjectCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectCreateResponse, + ) + + def retrieve( + self, + *, + project_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ProjectRetrieveResponse: + """ + Gets details about a specific project. + + Use this method to: + + - View project configuration + - Check project status + - Get project metadata + + ### Examples + + - Get project details: + + Retrieves information about a specific project. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.ProjectService/GetProject", + body=maybe_transform({"project_id": project_id}, project_retrieve_params.ProjectRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectRetrieveResponse, + ) + + def update( + self, + *, + automations_file_path: Optional[str] | NotGiven = NOT_GIVEN, + devcontainer_file_path: Optional[str] | NotGiven = NOT_GIVEN, + environment_class: Optional[ProjectEnvironmentClassParam] | NotGiven = NOT_GIVEN, + initializer: Optional[EnvironmentInitializerParam] | NotGiven = NOT_GIVEN, + name: Optional[str] | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + technical_description: Optional[str] | NotGiven = NOT_GIVEN, + # 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, + ) -> ProjectUpdateResponse: + """ + Updates a project's configuration. + + Use this method to: + + - Modify project settings + - Update environment class + - Change project name + - Configure initializers + + ### Examples + + - Update project name: + + Changes the project's display name. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + name: "New Project Name" + ``` + + - Update environment class: + + Changes the project's environment class. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + environmentClass: + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + automations_file_path: automations_file_path is the path to the automations file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches("^$|^[^/].*") + ``` + + devcontainer_file_path: devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches("^$|^[^/].*") + ``` + + initializer: initializer is the content initializer + + project_id: project_id specifies the project identifier + + 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 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.ProjectService/UpdateProject", + body=maybe_transform( + { + "automations_file_path": automations_file_path, + "devcontainer_file_path": devcontainer_file_path, + "environment_class": environment_class, + "initializer": initializer, + "name": name, + "project_id": project_id, + "technical_description": technical_description, + }, + project_update_params.ProjectUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectUpdateResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: project_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: project_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncProjectsPage[Project]: + """ + Lists projects with optional filtering. + + Use this method to: + + - View all accessible projects + - Browse project configurations + - Monitor project status + + ### Examples + + - List projects: + + Shows all projects with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing organizations + + 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._get_api_list( + "/gitpod.v1.ProjectService/ListProjects", + page=SyncProjectsPage[Project], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + project_list_params.ProjectListParams, + ), + 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, + }, + project_list_params.ProjectListParams, + ), + ), + model=Project, + method="post", + ) + + def delete( + self, + *, + project_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a project permanently. + + Use this method to: + + - Remove unused projects + - Clean up test projects + - Delete obsolete configurations + + ### Examples + + - Delete project: + + Permanently removes a project. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.ProjectService/DeleteProject", + body=maybe_transform({"project_id": project_id}, project_delete_params.ProjectDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def create_from_environment( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ProjectCreateFromEnvironmentResponse: + """ + Creates a new project using an existing environment as a template. + + Use this method to: + + - Clone environment configurations + - Create projects from templates + - Share environment setups + + ### Examples + + - Create from environment: + + Creates a project based on existing environment. + + ```yaml + name: "Frontend Project" + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.ProjectService/CreateProjectFromEnvironment", + body=maybe_transform( + { + "environment_id": environment_id, + "name": name, + }, + project_create_from_environment_params.ProjectCreateFromEnvironmentParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectCreateFromEnvironmentResponse, + ) + + +class AsyncProjectsResource(AsyncAPIResource): + @cached_property + def policies(self) -> AsyncPoliciesResource: + return AsyncPoliciesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncProjectsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncProjectsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncProjectsResourceWithStreamingResponse(self) + + async def create( + self, + *, + environment_class: ProjectEnvironmentClassParam, + initializer: EnvironmentInitializerParam, + automations_file_path: str | NotGiven = NOT_GIVEN, + devcontainer_file_path: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + technical_description: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ProjectCreateResponse: + """ + Creates a new project with specified configuration. + + Use this method to: + + - Set up development projects + - Configure project environments + - Define project settings + - Initialize project content + + ### Examples + + - Create basic project: + + Creates a project with minimal configuration. + + ```yaml + name: "Web Application" + environmentClass: + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + initializer: + specs: + - git: + remoteUri: "https://github.com/org/repo" + ``` + + - Create project with devcontainer: + + Creates a project with custom development container. + + ```yaml + name: "Backend Service" + environmentClass: + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + initializer: + specs: + - git: + remoteUri: "https://github.com/org/backend" + devcontainerFilePath: ".devcontainer/devcontainer.json" + automationsFilePath: ".gitpod/automations.yaml" + ``` + + Args: + initializer: initializer is the content initializer + + automations_file_path: automations_file_path is the path to the automations file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches("^$|^[^/].*") + ``` + + devcontainer_file_path: devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches("^$|^[^/].*") + ``` + + 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 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.ProjectService/CreateProject", + body=await async_maybe_transform( + { + "environment_class": environment_class, + "initializer": initializer, + "automations_file_path": automations_file_path, + "devcontainer_file_path": devcontainer_file_path, + "name": name, + "technical_description": technical_description, + }, + project_create_params.ProjectCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectCreateResponse, + ) + + async def retrieve( + self, + *, + project_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ProjectRetrieveResponse: + """ + Gets details about a specific project. + + Use this method to: + + - View project configuration + - Check project status + - Get project metadata + + ### Examples + + - Get project details: + + Retrieves information about a specific project. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.ProjectService/GetProject", + body=await async_maybe_transform({"project_id": project_id}, project_retrieve_params.ProjectRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectRetrieveResponse, + ) + + async def update( + self, + *, + automations_file_path: Optional[str] | NotGiven = NOT_GIVEN, + devcontainer_file_path: Optional[str] | NotGiven = NOT_GIVEN, + environment_class: Optional[ProjectEnvironmentClassParam] | NotGiven = NOT_GIVEN, + initializer: Optional[EnvironmentInitializerParam] | NotGiven = NOT_GIVEN, + name: Optional[str] | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + technical_description: Optional[str] | NotGiven = NOT_GIVEN, + # 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, + ) -> ProjectUpdateResponse: + """ + Updates a project's configuration. + + Use this method to: + + - Modify project settings + - Update environment class + - Change project name + - Configure initializers + + ### Examples + + - Update project name: + + Changes the project's display name. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + name: "New Project Name" + ``` + + - Update environment class: + + Changes the project's environment class. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + environmentClass: + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + automations_file_path: automations_file_path is the path to the automations file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches("^$|^[^/].*") + ``` + + devcontainer_file_path: devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches("^$|^[^/].*") + ``` + + initializer: initializer is the content initializer + + project_id: project_id specifies the project identifier + + 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 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.ProjectService/UpdateProject", + body=await async_maybe_transform( + { + "automations_file_path": automations_file_path, + "devcontainer_file_path": devcontainer_file_path, + "environment_class": environment_class, + "initializer": initializer, + "name": name, + "project_id": project_id, + "technical_description": technical_description, + }, + project_update_params.ProjectUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectUpdateResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: project_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: project_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Project, AsyncProjectsPage[Project]]: + """ + Lists projects with optional filtering. + + Use this method to: + + - View all accessible projects + - Browse project configurations + - Monitor project status + + ### Examples + + - List projects: + + Shows all projects with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing organizations + + 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._get_api_list( + "/gitpod.v1.ProjectService/ListProjects", + page=AsyncProjectsPage[Project], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + project_list_params.ProjectListParams, + ), + 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, + }, + project_list_params.ProjectListParams, + ), + ), + model=Project, + method="post", + ) + + async def delete( + self, + *, + project_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a project permanently. + + Use this method to: + + - Remove unused projects + - Clean up test projects + - Delete obsolete configurations + + ### Examples + + - Delete project: + + Permanently removes a project. + + ```yaml + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + ``` + + Args: + project_id: project_id specifies the project identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.ProjectService/DeleteProject", + body=await async_maybe_transform({"project_id": project_id}, project_delete_params.ProjectDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def create_from_environment( + self, + *, + environment_id: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ProjectCreateFromEnvironmentResponse: + """ + Creates a new project using an existing environment as a template. + + Use this method to: + + - Clone environment configurations + - Create projects from templates + - Share environment setups + + ### Examples + + - Create from environment: + + Creates a project based on existing environment. + + ```yaml + name: "Frontend Project" + environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + ``` + + Args: + environment_id: environment_id specifies the environment identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.ProjectService/CreateProjectFromEnvironment", + body=await async_maybe_transform( + { + "environment_id": environment_id, + "name": name, + }, + project_create_from_environment_params.ProjectCreateFromEnvironmentParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectCreateFromEnvironmentResponse, + ) + + +class ProjectsResourceWithRawResponse: + def __init__(self, projects: ProjectsResource) -> None: + self._projects = projects + + self.create = to_raw_response_wrapper( + projects.create, + ) + self.retrieve = to_raw_response_wrapper( + projects.retrieve, + ) + self.update = to_raw_response_wrapper( + projects.update, + ) + self.list = to_raw_response_wrapper( + projects.list, + ) + self.delete = to_raw_response_wrapper( + projects.delete, + ) + self.create_from_environment = to_raw_response_wrapper( + projects.create_from_environment, + ) + + @cached_property + def policies(self) -> PoliciesResourceWithRawResponse: + return PoliciesResourceWithRawResponse(self._projects.policies) + + +class AsyncProjectsResourceWithRawResponse: + def __init__(self, projects: AsyncProjectsResource) -> None: + self._projects = projects + + self.create = async_to_raw_response_wrapper( + projects.create, + ) + self.retrieve = async_to_raw_response_wrapper( + projects.retrieve, + ) + self.update = async_to_raw_response_wrapper( + projects.update, + ) + self.list = async_to_raw_response_wrapper( + projects.list, + ) + self.delete = async_to_raw_response_wrapper( + projects.delete, + ) + self.create_from_environment = async_to_raw_response_wrapper( + projects.create_from_environment, + ) + + @cached_property + def policies(self) -> AsyncPoliciesResourceWithRawResponse: + return AsyncPoliciesResourceWithRawResponse(self._projects.policies) + + +class ProjectsResourceWithStreamingResponse: + def __init__(self, projects: ProjectsResource) -> None: + self._projects = projects + + self.create = to_streamed_response_wrapper( + projects.create, + ) + self.retrieve = to_streamed_response_wrapper( + projects.retrieve, + ) + self.update = to_streamed_response_wrapper( + projects.update, + ) + self.list = to_streamed_response_wrapper( + projects.list, + ) + self.delete = to_streamed_response_wrapper( + projects.delete, + ) + self.create_from_environment = to_streamed_response_wrapper( + projects.create_from_environment, + ) + + @cached_property + def policies(self) -> PoliciesResourceWithStreamingResponse: + return PoliciesResourceWithStreamingResponse(self._projects.policies) + + +class AsyncProjectsResourceWithStreamingResponse: + def __init__(self, projects: AsyncProjectsResource) -> None: + self._projects = projects + + self.create = async_to_streamed_response_wrapper( + projects.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + projects.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + projects.update, + ) + self.list = async_to_streamed_response_wrapper( + projects.list, + ) + self.delete = async_to_streamed_response_wrapper( + projects.delete, + ) + self.create_from_environment = async_to_streamed_response_wrapper( + projects.create_from_environment, + ) + + @cached_property + def policies(self) -> AsyncPoliciesResourceWithStreamingResponse: + return AsyncPoliciesResourceWithStreamingResponse(self._projects.policies) diff --git a/src/gitpod/resources/runners/__init__.py b/src/gitpod/resources/runners/__init__.py new file mode 100644 index 0000000..27ce34c --- /dev/null +++ b/src/gitpod/resources/runners/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .runners import ( + RunnersResource, + AsyncRunnersResource, + RunnersResourceWithRawResponse, + AsyncRunnersResourceWithRawResponse, + RunnersResourceWithStreamingResponse, + AsyncRunnersResourceWithStreamingResponse, +) +from .policies import ( + PoliciesResource, + AsyncPoliciesResource, + PoliciesResourceWithRawResponse, + AsyncPoliciesResourceWithRawResponse, + PoliciesResourceWithStreamingResponse, + AsyncPoliciesResourceWithStreamingResponse, +) +from .configurations import ( + ConfigurationsResource, + AsyncConfigurationsResource, + ConfigurationsResourceWithRawResponse, + AsyncConfigurationsResourceWithRawResponse, + ConfigurationsResourceWithStreamingResponse, + AsyncConfigurationsResourceWithStreamingResponse, +) + +__all__ = [ + "ConfigurationsResource", + "AsyncConfigurationsResource", + "ConfigurationsResourceWithRawResponse", + "AsyncConfigurationsResourceWithRawResponse", + "ConfigurationsResourceWithStreamingResponse", + "AsyncConfigurationsResourceWithStreamingResponse", + "PoliciesResource", + "AsyncPoliciesResource", + "PoliciesResourceWithRawResponse", + "AsyncPoliciesResourceWithRawResponse", + "PoliciesResourceWithStreamingResponse", + "AsyncPoliciesResourceWithStreamingResponse", + "RunnersResource", + "AsyncRunnersResource", + "RunnersResourceWithRawResponse", + "AsyncRunnersResourceWithRawResponse", + "RunnersResourceWithStreamingResponse", + "AsyncRunnersResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/runners/configurations/__init__.py b/src/gitpod/resources/runners/configurations/__init__.py new file mode 100644 index 0000000..848f99c --- /dev/null +++ b/src/gitpod/resources/runners/configurations/__init__.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .schema import ( + SchemaResource, + AsyncSchemaResource, + SchemaResourceWithRawResponse, + AsyncSchemaResourceWithRawResponse, + SchemaResourceWithStreamingResponse, + AsyncSchemaResourceWithStreamingResponse, +) +from .configurations import ( + ConfigurationsResource, + AsyncConfigurationsResource, + ConfigurationsResourceWithRawResponse, + AsyncConfigurationsResourceWithRawResponse, + ConfigurationsResourceWithStreamingResponse, + AsyncConfigurationsResourceWithStreamingResponse, +) +from .scm_integrations import ( + ScmIntegrationsResource, + AsyncScmIntegrationsResource, + ScmIntegrationsResourceWithRawResponse, + AsyncScmIntegrationsResourceWithRawResponse, + ScmIntegrationsResourceWithStreamingResponse, + AsyncScmIntegrationsResourceWithStreamingResponse, +) +from .environment_classes import ( + EnvironmentClassesResource, + AsyncEnvironmentClassesResource, + EnvironmentClassesResourceWithRawResponse, + AsyncEnvironmentClassesResourceWithRawResponse, + EnvironmentClassesResourceWithStreamingResponse, + AsyncEnvironmentClassesResourceWithStreamingResponse, +) +from .host_authentication_tokens import ( + HostAuthenticationTokensResource, + AsyncHostAuthenticationTokensResource, + HostAuthenticationTokensResourceWithRawResponse, + AsyncHostAuthenticationTokensResourceWithRawResponse, + HostAuthenticationTokensResourceWithStreamingResponse, + AsyncHostAuthenticationTokensResourceWithStreamingResponse, +) + +__all__ = [ + "EnvironmentClassesResource", + "AsyncEnvironmentClassesResource", + "EnvironmentClassesResourceWithRawResponse", + "AsyncEnvironmentClassesResourceWithRawResponse", + "EnvironmentClassesResourceWithStreamingResponse", + "AsyncEnvironmentClassesResourceWithStreamingResponse", + "HostAuthenticationTokensResource", + "AsyncHostAuthenticationTokensResource", + "HostAuthenticationTokensResourceWithRawResponse", + "AsyncHostAuthenticationTokensResourceWithRawResponse", + "HostAuthenticationTokensResourceWithStreamingResponse", + "AsyncHostAuthenticationTokensResourceWithStreamingResponse", + "SchemaResource", + "AsyncSchemaResource", + "SchemaResourceWithRawResponse", + "AsyncSchemaResourceWithRawResponse", + "SchemaResourceWithStreamingResponse", + "AsyncSchemaResourceWithStreamingResponse", + "ScmIntegrationsResource", + "AsyncScmIntegrationsResource", + "ScmIntegrationsResourceWithRawResponse", + "AsyncScmIntegrationsResourceWithRawResponse", + "ScmIntegrationsResourceWithStreamingResponse", + "AsyncScmIntegrationsResourceWithStreamingResponse", + "ConfigurationsResource", + "AsyncConfigurationsResource", + "ConfigurationsResourceWithRawResponse", + "AsyncConfigurationsResourceWithRawResponse", + "ConfigurationsResourceWithStreamingResponse", + "AsyncConfigurationsResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/runners/configurations/configurations.py b/src/gitpod/resources/runners/configurations/configurations.py new file mode 100644 index 0000000..b9b2c27 --- /dev/null +++ b/src/gitpod/resources/runners/configurations/configurations.py @@ -0,0 +1,356 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .schema import ( + SchemaResource, + AsyncSchemaResource, + SchemaResourceWithRawResponse, + AsyncSchemaResourceWithRawResponse, + SchemaResourceWithStreamingResponse, + AsyncSchemaResourceWithStreamingResponse, +) +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.runners import configuration_validate_params +from .scm_integrations import ( + ScmIntegrationsResource, + AsyncScmIntegrationsResource, + ScmIntegrationsResourceWithRawResponse, + AsyncScmIntegrationsResourceWithRawResponse, + ScmIntegrationsResourceWithStreamingResponse, + AsyncScmIntegrationsResourceWithStreamingResponse, +) +from .environment_classes import ( + EnvironmentClassesResource, + AsyncEnvironmentClassesResource, + EnvironmentClassesResourceWithRawResponse, + AsyncEnvironmentClassesResourceWithRawResponse, + EnvironmentClassesResourceWithStreamingResponse, + AsyncEnvironmentClassesResourceWithStreamingResponse, +) +from .host_authentication_tokens import ( + HostAuthenticationTokensResource, + AsyncHostAuthenticationTokensResource, + HostAuthenticationTokensResourceWithRawResponse, + AsyncHostAuthenticationTokensResourceWithRawResponse, + HostAuthenticationTokensResourceWithStreamingResponse, + AsyncHostAuthenticationTokensResourceWithStreamingResponse, +) +from ....types.shared_params.environment_class import EnvironmentClass +from ....types.runners.configuration_validate_response import ConfigurationValidateResponse + +__all__ = ["ConfigurationsResource", "AsyncConfigurationsResource"] + + +class ConfigurationsResource(SyncAPIResource): + @cached_property + def environment_classes(self) -> EnvironmentClassesResource: + return EnvironmentClassesResource(self._client) + + @cached_property + def host_authentication_tokens(self) -> HostAuthenticationTokensResource: + return HostAuthenticationTokensResource(self._client) + + @cached_property + def schema(self) -> SchemaResource: + return SchemaResource(self._client) + + @cached_property + def scm_integrations(self) -> ScmIntegrationsResource: + return ScmIntegrationsResource(self._client) + + @cached_property + def with_raw_response(self) -> ConfigurationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return ConfigurationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ConfigurationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return ConfigurationsResourceWithStreamingResponse(self) + + def validate( + self, + *, + environment_class: EnvironmentClass | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + scm_integration: configuration_validate_params.ScmIntegration | NotGiven = NOT_GIVEN, + # 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, + ) -> ConfigurationValidateResponse: + """ + Validates a runner configuration. + + Use this method to: + + - Check configuration validity + - Verify integration settings + - Validate environment classes + + ### Examples + + - Validate SCM integration: + + Checks if an SCM integration is valid. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + scmIntegration: + id: "integration-id" + scmId: "github" + host: "github.com" + oauthClientId: "client_id" + oauthPlaintextClientSecret: "client_secret" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/ValidateRunnerConfiguration", + body=maybe_transform( + { + "environment_class": environment_class, + "runner_id": runner_id, + "scm_integration": scm_integration, + }, + configuration_validate_params.ConfigurationValidateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConfigurationValidateResponse, + ) + + +class AsyncConfigurationsResource(AsyncAPIResource): + @cached_property + def environment_classes(self) -> AsyncEnvironmentClassesResource: + return AsyncEnvironmentClassesResource(self._client) + + @cached_property + def host_authentication_tokens(self) -> AsyncHostAuthenticationTokensResource: + return AsyncHostAuthenticationTokensResource(self._client) + + @cached_property + def schema(self) -> AsyncSchemaResource: + return AsyncSchemaResource(self._client) + + @cached_property + def scm_integrations(self) -> AsyncScmIntegrationsResource: + return AsyncScmIntegrationsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncConfigurationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncConfigurationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncConfigurationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncConfigurationsResourceWithStreamingResponse(self) + + async def validate( + self, + *, + environment_class: EnvironmentClass | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + scm_integration: configuration_validate_params.ScmIntegration | NotGiven = NOT_GIVEN, + # 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, + ) -> ConfigurationValidateResponse: + """ + Validates a runner configuration. + + Use this method to: + + - Check configuration validity + - Verify integration settings + - Validate environment classes + + ### Examples + + - Validate SCM integration: + + Checks if an SCM integration is valid. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + scmIntegration: + id: "integration-id" + scmId: "github" + host: "github.com" + oauthClientId: "client_id" + oauthPlaintextClientSecret: "client_secret" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/ValidateRunnerConfiguration", + body=await async_maybe_transform( + { + "environment_class": environment_class, + "runner_id": runner_id, + "scm_integration": scm_integration, + }, + configuration_validate_params.ConfigurationValidateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConfigurationValidateResponse, + ) + + +class ConfigurationsResourceWithRawResponse: + def __init__(self, configurations: ConfigurationsResource) -> None: + self._configurations = configurations + + self.validate = to_raw_response_wrapper( + configurations.validate, + ) + + @cached_property + def environment_classes(self) -> EnvironmentClassesResourceWithRawResponse: + return EnvironmentClassesResourceWithRawResponse(self._configurations.environment_classes) + + @cached_property + def host_authentication_tokens(self) -> HostAuthenticationTokensResourceWithRawResponse: + return HostAuthenticationTokensResourceWithRawResponse(self._configurations.host_authentication_tokens) + + @cached_property + def schema(self) -> SchemaResourceWithRawResponse: + return SchemaResourceWithRawResponse(self._configurations.schema) + + @cached_property + def scm_integrations(self) -> ScmIntegrationsResourceWithRawResponse: + return ScmIntegrationsResourceWithRawResponse(self._configurations.scm_integrations) + + +class AsyncConfigurationsResourceWithRawResponse: + def __init__(self, configurations: AsyncConfigurationsResource) -> None: + self._configurations = configurations + + self.validate = async_to_raw_response_wrapper( + configurations.validate, + ) + + @cached_property + def environment_classes(self) -> AsyncEnvironmentClassesResourceWithRawResponse: + return AsyncEnvironmentClassesResourceWithRawResponse(self._configurations.environment_classes) + + @cached_property + def host_authentication_tokens(self) -> AsyncHostAuthenticationTokensResourceWithRawResponse: + return AsyncHostAuthenticationTokensResourceWithRawResponse(self._configurations.host_authentication_tokens) + + @cached_property + def schema(self) -> AsyncSchemaResourceWithRawResponse: + return AsyncSchemaResourceWithRawResponse(self._configurations.schema) + + @cached_property + def scm_integrations(self) -> AsyncScmIntegrationsResourceWithRawResponse: + return AsyncScmIntegrationsResourceWithRawResponse(self._configurations.scm_integrations) + + +class ConfigurationsResourceWithStreamingResponse: + def __init__(self, configurations: ConfigurationsResource) -> None: + self._configurations = configurations + + self.validate = to_streamed_response_wrapper( + configurations.validate, + ) + + @cached_property + def environment_classes(self) -> EnvironmentClassesResourceWithStreamingResponse: + return EnvironmentClassesResourceWithStreamingResponse(self._configurations.environment_classes) + + @cached_property + def host_authentication_tokens(self) -> HostAuthenticationTokensResourceWithStreamingResponse: + return HostAuthenticationTokensResourceWithStreamingResponse(self._configurations.host_authentication_tokens) + + @cached_property + def schema(self) -> SchemaResourceWithStreamingResponse: + return SchemaResourceWithStreamingResponse(self._configurations.schema) + + @cached_property + def scm_integrations(self) -> ScmIntegrationsResourceWithStreamingResponse: + return ScmIntegrationsResourceWithStreamingResponse(self._configurations.scm_integrations) + + +class AsyncConfigurationsResourceWithStreamingResponse: + def __init__(self, configurations: AsyncConfigurationsResource) -> None: + self._configurations = configurations + + self.validate = async_to_streamed_response_wrapper( + configurations.validate, + ) + + @cached_property + def environment_classes(self) -> AsyncEnvironmentClassesResourceWithStreamingResponse: + return AsyncEnvironmentClassesResourceWithStreamingResponse(self._configurations.environment_classes) + + @cached_property + def host_authentication_tokens(self) -> AsyncHostAuthenticationTokensResourceWithStreamingResponse: + return AsyncHostAuthenticationTokensResourceWithStreamingResponse( + self._configurations.host_authentication_tokens + ) + + @cached_property + def schema(self) -> AsyncSchemaResourceWithStreamingResponse: + return AsyncSchemaResourceWithStreamingResponse(self._configurations.schema) + + @cached_property + def scm_integrations(self) -> AsyncScmIntegrationsResourceWithStreamingResponse: + return AsyncScmIntegrationsResourceWithStreamingResponse(self._configurations.scm_integrations) diff --git a/src/gitpod/resources/runners/configurations/environment_classes.py b/src/gitpod/resources/runners/configurations/environment_classes.py new file mode 100644 index 0000000..ba2137c --- /dev/null +++ b/src/gitpod/resources/runners/configurations/environment_classes.py @@ -0,0 +1,674 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional + +import httpx + +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncEnvironmentClassesPage, AsyncEnvironmentClassesPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.runners.configurations import ( + environment_class_list_params, + environment_class_create_params, + environment_class_update_params, + environment_class_retrieve_params, +) +from ....types.shared.environment_class import EnvironmentClass +from ....types.shared_params.field_value import FieldValue +from ....types.runners.configurations.environment_class_create_response import EnvironmentClassCreateResponse +from ....types.runners.configurations.environment_class_retrieve_response import EnvironmentClassRetrieveResponse + +__all__ = ["EnvironmentClassesResource", "AsyncEnvironmentClassesResource"] + + +class EnvironmentClassesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> EnvironmentClassesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return EnvironmentClassesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> EnvironmentClassesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return EnvironmentClassesResourceWithStreamingResponse(self) + + def create( + self, + *, + configuration: Iterable[FieldValue] | NotGiven = NOT_GIVEN, + description: str | NotGiven = NOT_GIVEN, + display_name: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentClassCreateResponse: + """ + Creates a new environment class for a runner. + + Use this method to: + + - Define compute resources + - Configure environment settings + - Set up runtime options + + ### Examples + + - Create environment class: + + Creates a new environment configuration. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + displayName: "Large Instance" + description: "8 CPU, 16GB RAM" + configuration: + - key: "cpu" + value: "8" + - key: "memory" + value: "16384" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/CreateEnvironmentClass", + body=maybe_transform( + { + "configuration": configuration, + "description": description, + "display_name": display_name, + "runner_id": runner_id, + }, + environment_class_create_params.EnvironmentClassCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentClassCreateResponse, + ) + + def retrieve( + self, + *, + environment_class_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentClassRetrieveResponse: + """ + Gets details about a specific environment class. + + Use this method to: + + - View class configuration + - Check resource settings + - Verify availability + + ### Examples + + - Get class details: + + Retrieves information about a specific class. + + ```yaml + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/GetEnvironmentClass", + body=maybe_transform( + {"environment_class_id": environment_class_id}, + environment_class_retrieve_params.EnvironmentClassRetrieveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentClassRetrieveResponse, + ) + + def update( + self, + *, + description: Optional[str] | NotGiven = NOT_GIVEN, + display_name: Optional[str] | NotGiven = NOT_GIVEN, + enabled: Optional[bool] | NotGiven = NOT_GIVEN, + environment_class_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an environment class. + + Use this method to: + + - Modify class settings + - Update resource limits + - Change availability + + ### Examples + + - Update class: + + Changes class configuration. + + ```yaml + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + displayName: "Updated Large Instance" + description: "16 CPU, 32GB RAM" + enabled: true + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/UpdateEnvironmentClass", + body=maybe_transform( + { + "description": description, + "display_name": display_name, + "enabled": enabled, + "environment_class_id": environment_class_id, + }, + environment_class_update_params.EnvironmentClassUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: environment_class_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: environment_class_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncEnvironmentClassesPage[EnvironmentClass]: + """ + Lists environment classes with optional filtering. + + Use this method to: + + - View available classes + - Filter by capability + - Check enabled status + + ### Examples + + - List all classes: + + Shows all environment classes. + + ```yaml + pagination: + pageSize: 20 + ``` + + - Filter enabled classes: + + Lists only enabled environment classes. + + ```yaml + filter: + enabled: true + pagination: + pageSize: 20 + ``` + + buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + + Args: + pagination: pagination contains the pagination options for listing environment classes + + 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._get_api_list( + "/gitpod.v1.RunnerConfigurationService/ListEnvironmentClasses", + page=SyncEnvironmentClassesPage[EnvironmentClass], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + environment_class_list_params.EnvironmentClassListParams, + ), + 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, + }, + environment_class_list_params.EnvironmentClassListParams, + ), + ), + model=EnvironmentClass, + method="post", + ) + + +class AsyncEnvironmentClassesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncEnvironmentClassesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncEnvironmentClassesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncEnvironmentClassesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncEnvironmentClassesResourceWithStreamingResponse(self) + + async def create( + self, + *, + configuration: Iterable[FieldValue] | NotGiven = NOT_GIVEN, + description: str | NotGiven = NOT_GIVEN, + display_name: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentClassCreateResponse: + """ + Creates a new environment class for a runner. + + Use this method to: + + - Define compute resources + - Configure environment settings + - Set up runtime options + + ### Examples + + - Create environment class: + + Creates a new environment configuration. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + displayName: "Large Instance" + description: "8 CPU, 16GB RAM" + configuration: + - key: "cpu" + value: "8" + - key: "memory" + value: "16384" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/CreateEnvironmentClass", + body=await async_maybe_transform( + { + "configuration": configuration, + "description": description, + "display_name": display_name, + "runner_id": runner_id, + }, + environment_class_create_params.EnvironmentClassCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentClassCreateResponse, + ) + + async def retrieve( + self, + *, + environment_class_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> EnvironmentClassRetrieveResponse: + """ + Gets details about a specific environment class. + + Use this method to: + + - View class configuration + - Check resource settings + - Verify availability + + ### Examples + + - Get class details: + + Retrieves information about a specific class. + + ```yaml + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/GetEnvironmentClass", + body=await async_maybe_transform( + {"environment_class_id": environment_class_id}, + environment_class_retrieve_params.EnvironmentClassRetrieveParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EnvironmentClassRetrieveResponse, + ) + + async def update( + self, + *, + description: Optional[str] | NotGiven = NOT_GIVEN, + display_name: Optional[str] | NotGiven = NOT_GIVEN, + enabled: Optional[bool] | NotGiven = NOT_GIVEN, + environment_class_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an environment class. + + Use this method to: + + - Modify class settings + - Update resource limits + - Change availability + + ### Examples + + - Update class: + + Changes class configuration. + + ```yaml + environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + displayName: "Updated Large Instance" + description: "16 CPU, 32GB RAM" + enabled: true + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/UpdateEnvironmentClass", + body=await async_maybe_transform( + { + "description": description, + "display_name": display_name, + "enabled": enabled, + "environment_class_id": environment_class_id, + }, + environment_class_update_params.EnvironmentClassUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: environment_class_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: environment_class_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[EnvironmentClass, AsyncEnvironmentClassesPage[EnvironmentClass]]: + """ + Lists environment classes with optional filtering. + + Use this method to: + + - View available classes + - Filter by capability + - Check enabled status + + ### Examples + + - List all classes: + + Shows all environment classes. + + ```yaml + pagination: + pageSize: 20 + ``` + + - Filter enabled classes: + + Lists only enabled environment classes. + + ```yaml + filter: + enabled: true + pagination: + pageSize: 20 + ``` + + buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + + Args: + pagination: pagination contains the pagination options for listing environment classes + + 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._get_api_list( + "/gitpod.v1.RunnerConfigurationService/ListEnvironmentClasses", + page=AsyncEnvironmentClassesPage[EnvironmentClass], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + environment_class_list_params.EnvironmentClassListParams, + ), + 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, + }, + environment_class_list_params.EnvironmentClassListParams, + ), + ), + model=EnvironmentClass, + method="post", + ) + + +class EnvironmentClassesResourceWithRawResponse: + def __init__(self, environment_classes: EnvironmentClassesResource) -> None: + self._environment_classes = environment_classes + + self.create = to_raw_response_wrapper( + environment_classes.create, + ) + self.retrieve = to_raw_response_wrapper( + environment_classes.retrieve, + ) + self.update = to_raw_response_wrapper( + environment_classes.update, + ) + self.list = to_raw_response_wrapper( + environment_classes.list, + ) + + +class AsyncEnvironmentClassesResourceWithRawResponse: + def __init__(self, environment_classes: AsyncEnvironmentClassesResource) -> None: + self._environment_classes = environment_classes + + self.create = async_to_raw_response_wrapper( + environment_classes.create, + ) + self.retrieve = async_to_raw_response_wrapper( + environment_classes.retrieve, + ) + self.update = async_to_raw_response_wrapper( + environment_classes.update, + ) + self.list = async_to_raw_response_wrapper( + environment_classes.list, + ) + + +class EnvironmentClassesResourceWithStreamingResponse: + def __init__(self, environment_classes: EnvironmentClassesResource) -> None: + self._environment_classes = environment_classes + + self.create = to_streamed_response_wrapper( + environment_classes.create, + ) + self.retrieve = to_streamed_response_wrapper( + environment_classes.retrieve, + ) + self.update = to_streamed_response_wrapper( + environment_classes.update, + ) + self.list = to_streamed_response_wrapper( + environment_classes.list, + ) + + +class AsyncEnvironmentClassesResourceWithStreamingResponse: + def __init__(self, environment_classes: AsyncEnvironmentClassesResource) -> None: + self._environment_classes = environment_classes + + self.create = async_to_streamed_response_wrapper( + environment_classes.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + environment_classes.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + environment_classes.update, + ) + self.list = async_to_streamed_response_wrapper( + environment_classes.list, + ) diff --git a/src/gitpod/resources/runners/configurations/host_authentication_tokens.py b/src/gitpod/resources/runners/configurations/host_authentication_tokens.py new file mode 100644 index 0000000..af044ec --- /dev/null +++ b/src/gitpod/resources/runners/configurations/host_authentication_tokens.py @@ -0,0 +1,1149 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from datetime import datetime + +import httpx + +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncTokensPage, AsyncTokensPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.runners.configurations import ( + HostAuthenticationTokenSource, + host_authentication_token_list_params, + host_authentication_token_create_params, + host_authentication_token_delete_params, + host_authentication_token_update_params, + host_authentication_token_retrieve_params, +) +from ....types.runners.configurations.host_authentication_token import HostAuthenticationToken +from ....types.runners.configurations.host_authentication_token_source import HostAuthenticationTokenSource +from ....types.runners.configurations.host_authentication_token_create_response import ( + HostAuthenticationTokenCreateResponse, +) +from ....types.runners.configurations.host_authentication_token_retrieve_response import ( + HostAuthenticationTokenRetrieveResponse, +) + +__all__ = ["HostAuthenticationTokensResource", "AsyncHostAuthenticationTokensResource"] + + +class HostAuthenticationTokensResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> HostAuthenticationTokensResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return HostAuthenticationTokensResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> HostAuthenticationTokensResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return HostAuthenticationTokensResourceWithStreamingResponse(self) + + def create( + self, + *, + token: str | NotGiven = NOT_GIVEN, + expires_at: Union[str, datetime] | NotGiven = NOT_GIVEN, + host: str | NotGiven = NOT_GIVEN, + refresh_token: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + source: HostAuthenticationTokenSource | NotGiven = NOT_GIVEN, + user_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> HostAuthenticationTokenCreateResponse: + """ + Creates a new authentication token for accessing remote hosts. + + Use this method to: + + - Set up SCM authentication + - Configure OAuth credentials + - Manage PAT tokens + + ### Examples + + - Create OAuth token: + + Creates a new OAuth-based authentication token. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + host: "github.com" + token: "gho_xxxxxxxxxxxx" + source: HOST_AUTHENTICATION_TOKEN_SOURCE_OAUTH + expiresAt: "2024-12-31T23:59:59Z" + refreshToken: "ghr_xxxxxxxxxxxx" + ``` + + Args: + expires_at: A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + + 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.RunnerConfigurationService/CreateHostAuthenticationToken", + body=maybe_transform( + { + "token": token, + "expires_at": expires_at, + "host": host, + "refresh_token": refresh_token, + "runner_id": runner_id, + "source": source, + "user_id": user_id, + }, + host_authentication_token_create_params.HostAuthenticationTokenCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=HostAuthenticationTokenCreateResponse, + ) + + def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> HostAuthenticationTokenRetrieveResponse: + """ + Gets details about a specific host authentication token. + + Use this method to: + + - View token information + - Check token expiration + - Verify token validity + + ### Examples + + - Get token details: + + Retrieves information about a specific token. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/GetHostAuthenticationToken", + body=maybe_transform( + {"id": id}, host_authentication_token_retrieve_params.HostAuthenticationTokenRetrieveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=HostAuthenticationTokenRetrieveResponse, + ) + + def update( + self, + *, + id: str | NotGiven = NOT_GIVEN, + token: Optional[str] | NotGiven = NOT_GIVEN, + expires_at: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + refresh_token: Optional[str] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an existing host authentication token. + + Use this method to: + + - Refresh token values + - Update expiration + - Modify token settings + + ### Examples + + - Update token: + + Updates token value and expiration. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + token: "gho_xxxxxxxxxxxx" + expiresAt: "2024-12-31T23:59:59Z" + refreshToken: "ghr_xxxxxxxxxxxx" + ``` + + Args: + expires_at: A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + + 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.RunnerConfigurationService/UpdateHostAuthenticationToken", + body=maybe_transform( + { + "id": id, + "token": token, + "expires_at": expires_at, + "refresh_token": refresh_token, + }, + host_authentication_token_update_params.HostAuthenticationTokenUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: host_authentication_token_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: host_authentication_token_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncTokensPage[HostAuthenticationToken]: + """ + Lists host authentication tokens with optional filtering. + + Use this method to: + + - View all tokens + - Filter by runner or user + - Monitor token status + + ### Examples + + - List all tokens: + + Shows all tokens with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + - Filter by runner: + + Lists tokens for a specific runner. + + ```yaml + filter: + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + pagination: + pageSize: 20 + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/gitpod.v1.RunnerConfigurationService/ListHostAuthenticationTokens", + page=SyncTokensPage[HostAuthenticationToken], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + host_authentication_token_list_params.HostAuthenticationTokenListParams, + ), + 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, + }, + host_authentication_token_list_params.HostAuthenticationTokenListParams, + ), + ), + model=HostAuthenticationToken, + method="post", + ) + + def delete( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a host authentication token. + + Use this method to: + + - Remove unused tokens + - Revoke access + - Clean up expired tokens + + ### Examples + + - Delete token: + + Permanently removes a token. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/DeleteHostAuthenticationToken", + body=maybe_transform( + {"id": id}, host_authentication_token_delete_params.HostAuthenticationTokenDeleteParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncHostAuthenticationTokensResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncHostAuthenticationTokensResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncHostAuthenticationTokensResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncHostAuthenticationTokensResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncHostAuthenticationTokensResourceWithStreamingResponse(self) + + async def create( + self, + *, + token: str | NotGiven = NOT_GIVEN, + expires_at: Union[str, datetime] | NotGiven = NOT_GIVEN, + host: str | NotGiven = NOT_GIVEN, + refresh_token: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + source: HostAuthenticationTokenSource | NotGiven = NOT_GIVEN, + user_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> HostAuthenticationTokenCreateResponse: + """ + Creates a new authentication token for accessing remote hosts. + + Use this method to: + + - Set up SCM authentication + - Configure OAuth credentials + - Manage PAT tokens + + ### Examples + + - Create OAuth token: + + Creates a new OAuth-based authentication token. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + host: "github.com" + token: "gho_xxxxxxxxxxxx" + source: HOST_AUTHENTICATION_TOKEN_SOURCE_OAUTH + expiresAt: "2024-12-31T23:59:59Z" + refreshToken: "ghr_xxxxxxxxxxxx" + ``` + + Args: + expires_at: A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + + 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.RunnerConfigurationService/CreateHostAuthenticationToken", + body=await async_maybe_transform( + { + "token": token, + "expires_at": expires_at, + "host": host, + "refresh_token": refresh_token, + "runner_id": runner_id, + "source": source, + "user_id": user_id, + }, + host_authentication_token_create_params.HostAuthenticationTokenCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=HostAuthenticationTokenCreateResponse, + ) + + async def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> HostAuthenticationTokenRetrieveResponse: + """ + Gets details about a specific host authentication token. + + Use this method to: + + - View token information + - Check token expiration + - Verify token validity + + ### Examples + + - Get token details: + + Retrieves information about a specific token. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/GetHostAuthenticationToken", + body=await async_maybe_transform( + {"id": id}, host_authentication_token_retrieve_params.HostAuthenticationTokenRetrieveParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=HostAuthenticationTokenRetrieveResponse, + ) + + async def update( + self, + *, + id: str | NotGiven = NOT_GIVEN, + token: Optional[str] | NotGiven = NOT_GIVEN, + expires_at: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + refresh_token: Optional[str] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an existing host authentication token. + + Use this method to: + + - Refresh token values + - Update expiration + - Modify token settings + + ### Examples + + - Update token: + + Updates token value and expiration. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + token: "gho_xxxxxxxxxxxx" + expiresAt: "2024-12-31T23:59:59Z" + refreshToken: "ghr_xxxxxxxxxxxx" + ``` + + Args: + expires_at: A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + + 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.RunnerConfigurationService/UpdateHostAuthenticationToken", + body=await async_maybe_transform( + { + "id": id, + "token": token, + "expires_at": expires_at, + "refresh_token": refresh_token, + }, + host_authentication_token_update_params.HostAuthenticationTokenUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: host_authentication_token_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: host_authentication_token_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[HostAuthenticationToken, AsyncTokensPage[HostAuthenticationToken]]: + """ + Lists host authentication tokens with optional filtering. + + Use this method to: + + - View all tokens + - Filter by runner or user + - Monitor token status + + ### Examples + + - List all tokens: + + Shows all tokens with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + - Filter by runner: + + Lists tokens for a specific runner. + + ```yaml + filter: + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + pagination: + pageSize: 20 + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/gitpod.v1.RunnerConfigurationService/ListHostAuthenticationTokens", + page=AsyncTokensPage[HostAuthenticationToken], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + host_authentication_token_list_params.HostAuthenticationTokenListParams, + ), + 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, + }, + host_authentication_token_list_params.HostAuthenticationTokenListParams, + ), + ), + model=HostAuthenticationToken, + method="post", + ) + + async def delete( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a host authentication token. + + Use this method to: + + - Remove unused tokens + - Revoke access + - Clean up expired tokens + + ### Examples + + - Delete token: + + Permanently removes a token. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/DeleteHostAuthenticationToken", + body=await async_maybe_transform( + {"id": id}, host_authentication_token_delete_params.HostAuthenticationTokenDeleteParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class HostAuthenticationTokensResourceWithRawResponse: + def __init__(self, host_authentication_tokens: HostAuthenticationTokensResource) -> None: + self._host_authentication_tokens = host_authentication_tokens + + self.create = to_raw_response_wrapper( + host_authentication_tokens.create, + ) + self.retrieve = to_raw_response_wrapper( + host_authentication_tokens.retrieve, + ) + self.update = to_raw_response_wrapper( + host_authentication_tokens.update, + ) + self.list = to_raw_response_wrapper( + host_authentication_tokens.list, + ) + self.delete = to_raw_response_wrapper( + host_authentication_tokens.delete, + ) + + +class AsyncHostAuthenticationTokensResourceWithRawResponse: + def __init__(self, host_authentication_tokens: AsyncHostAuthenticationTokensResource) -> None: + self._host_authentication_tokens = host_authentication_tokens + + self.create = async_to_raw_response_wrapper( + host_authentication_tokens.create, + ) + self.retrieve = async_to_raw_response_wrapper( + host_authentication_tokens.retrieve, + ) + self.update = async_to_raw_response_wrapper( + host_authentication_tokens.update, + ) + self.list = async_to_raw_response_wrapper( + host_authentication_tokens.list, + ) + self.delete = async_to_raw_response_wrapper( + host_authentication_tokens.delete, + ) + + +class HostAuthenticationTokensResourceWithStreamingResponse: + def __init__(self, host_authentication_tokens: HostAuthenticationTokensResource) -> None: + self._host_authentication_tokens = host_authentication_tokens + + self.create = to_streamed_response_wrapper( + host_authentication_tokens.create, + ) + self.retrieve = to_streamed_response_wrapper( + host_authentication_tokens.retrieve, + ) + self.update = to_streamed_response_wrapper( + host_authentication_tokens.update, + ) + self.list = to_streamed_response_wrapper( + host_authentication_tokens.list, + ) + self.delete = to_streamed_response_wrapper( + host_authentication_tokens.delete, + ) + + +class AsyncHostAuthenticationTokensResourceWithStreamingResponse: + def __init__(self, host_authentication_tokens: AsyncHostAuthenticationTokensResource) -> None: + self._host_authentication_tokens = host_authentication_tokens + + self.create = async_to_streamed_response_wrapper( + host_authentication_tokens.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + host_authentication_tokens.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + host_authentication_tokens.update, + ) + self.list = async_to_streamed_response_wrapper( + host_authentication_tokens.list, + ) + self.delete = async_to_streamed_response_wrapper( + host_authentication_tokens.delete, + ) diff --git a/src/gitpod/resources/runners/configurations/schema.py b/src/gitpod/resources/runners/configurations/schema.py new file mode 100644 index 0000000..06963e1 --- /dev/null +++ b/src/gitpod/resources/runners/configurations/schema.py @@ -0,0 +1,195 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.runners.configurations import schema_retrieve_params +from ....types.runners.configurations.schema_retrieve_response import SchemaRetrieveResponse + +__all__ = ["SchemaResource", "AsyncSchemaResource"] + + +class SchemaResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SchemaResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return SchemaResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SchemaResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return SchemaResourceWithStreamingResponse(self) + + def retrieve( + self, + *, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> SchemaRetrieveResponse: + """ + Gets the latest runner configuration schema. + + Use this method to: + + - View available settings + - Check configuration options + - Validate configurations + + ### Examples + + - Get schema: + + Retrieves configuration schema for a runner. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/GetRunnerConfigurationSchema", + body=maybe_transform({"runner_id": runner_id}, schema_retrieve_params.SchemaRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SchemaRetrieveResponse, + ) + + +class AsyncSchemaResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSchemaResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncSchemaResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSchemaResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncSchemaResourceWithStreamingResponse(self) + + async def retrieve( + self, + *, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> SchemaRetrieveResponse: + """ + Gets the latest runner configuration schema. + + Use this method to: + + - View available settings + - Check configuration options + - Validate configurations + + ### Examples + + - Get schema: + + Retrieves configuration schema for a runner. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/GetRunnerConfigurationSchema", + body=await async_maybe_transform({"runner_id": runner_id}, schema_retrieve_params.SchemaRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SchemaRetrieveResponse, + ) + + +class SchemaResourceWithRawResponse: + def __init__(self, schema: SchemaResource) -> None: + self._schema = schema + + self.retrieve = to_raw_response_wrapper( + schema.retrieve, + ) + + +class AsyncSchemaResourceWithRawResponse: + def __init__(self, schema: AsyncSchemaResource) -> None: + self._schema = schema + + self.retrieve = async_to_raw_response_wrapper( + schema.retrieve, + ) + + +class SchemaResourceWithStreamingResponse: + def __init__(self, schema: SchemaResource) -> None: + self._schema = schema + + self.retrieve = to_streamed_response_wrapper( + schema.retrieve, + ) + + +class AsyncSchemaResourceWithStreamingResponse: + def __init__(self, schema: AsyncSchemaResource) -> None: + self._schema = schema + + self.retrieve = async_to_streamed_response_wrapper( + schema.retrieve, + ) diff --git a/src/gitpod/resources/runners/configurations/scm_integrations.py b/src/gitpod/resources/runners/configurations/scm_integrations.py new file mode 100644 index 0000000..2947b2e --- /dev/null +++ b/src/gitpod/resources/runners/configurations/scm_integrations.py @@ -0,0 +1,826 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncIntegrationsPage, AsyncIntegrationsPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.runners.configurations import ( + scm_integration_list_params, + scm_integration_create_params, + scm_integration_delete_params, + scm_integration_update_params, + scm_integration_retrieve_params, +) +from ....types.runners.configurations.scm_integration import ScmIntegration +from ....types.runners.configurations.scm_integration_create_response import ScmIntegrationCreateResponse +from ....types.runners.configurations.scm_integration_retrieve_response import ScmIntegrationRetrieveResponse + +__all__ = ["ScmIntegrationsResource", "AsyncScmIntegrationsResource"] + + +class ScmIntegrationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ScmIntegrationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return ScmIntegrationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ScmIntegrationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return ScmIntegrationsResourceWithStreamingResponse(self) + + def create( + self, + *, + host: str | NotGiven = NOT_GIVEN, + issuer_url: Optional[str] | NotGiven = NOT_GIVEN, + oauth_client_id: Optional[str] | NotGiven = NOT_GIVEN, + oauth_plaintext_client_secret: Optional[str] | NotGiven = NOT_GIVEN, + pat: bool | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + scm_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ScmIntegrationCreateResponse: + """ + Creates a new SCM integration for a runner. + + Use this method to: + + - Configure source control access + - Set up repository integrations + - Enable code synchronization + + ### Examples + + - Create GitHub integration: + + Sets up GitHub SCM integration. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + scmId: "github" + host: "github.com" + oauthClientId: "client_id" + oauthPlaintextClientSecret: "client_secret" + ``` + + Args: + issuer_url: issuer_url can be set to override the authentication provider URL, if it doesn't + match the SCM host. + + oauth_client_id: oauth_client_id is the OAuth app's client ID, if OAuth is configured. If + configured, oauth_plaintext_client_secret must also be set. + + oauth_plaintext_client_secret: oauth_plaintext_client_secret is the OAuth app's client secret in clear text. + This will first be encrypted with the runner's public key before being stored. + + scm_id: scm_id references the scm_id in the runner's configuration schema that this + integration is 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.RunnerConfigurationService/CreateSCMIntegration", + body=maybe_transform( + { + "host": host, + "issuer_url": issuer_url, + "oauth_client_id": oauth_client_id, + "oauth_plaintext_client_secret": oauth_plaintext_client_secret, + "pat": pat, + "runner_id": runner_id, + "scm_id": scm_id, + }, + scm_integration_create_params.ScmIntegrationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ScmIntegrationCreateResponse, + ) + + def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ScmIntegrationRetrieveResponse: + """ + Gets details about a specific SCM integration. + + Use this method to: + + - View integration settings + - Check integration status + - Verify configuration + + ### Examples + + - Get integration details: + + Retrieves information about a specific integration. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/GetSCMIntegration", + body=maybe_transform({"id": id}, scm_integration_retrieve_params.ScmIntegrationRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ScmIntegrationRetrieveResponse, + ) + + def update( + self, + *, + id: str | NotGiven = NOT_GIVEN, + issuer_url: Optional[str] | NotGiven = NOT_GIVEN, + oauth_client_id: Optional[str] | NotGiven = NOT_GIVEN, + oauth_plaintext_client_secret: Optional[str] | NotGiven = NOT_GIVEN, + pat: Optional[bool] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an existing SCM integration. + + Use this method to: + + - Modify integration settings + - Update credentials + - Change configuration + + ### Examples + + - Update integration: + + Updates OAuth credentials. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + oauthClientId: "new_client_id" + oauthPlaintextClientSecret: "new_client_secret" + ``` + + Args: + issuer_url: issuer_url can be set to override the authentication provider URL, if it doesn't + match the SCM host. + + oauth_client_id: oauth_client_id can be set to update the OAuth app's client ID. If an empty + string is set, the OAuth configuration will be removed (regardless of whether a + client secret is set), and any existing Host Authentication Tokens for the SCM + integration's runner and host that were created using the OAuth app will be + deleted. This might lead to users being unable to access their repositories + until they re-authenticate. + + oauth_plaintext_client_secret: oauth_plaintext_client_secret can be set to update the OAuth app's client + secret. The cleartext secret will be encrypted with the runner's public key + before being stored. + + pat: pat can be set to enable or disable Personal Access Tokens support. When + disabling PATs, any existing Host Authentication Tokens for the SCM + integration's runner and host that were created using a PAT will be deleted. + This might lead to users being unable to access their repositories until they + re-authenticate. + + 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.RunnerConfigurationService/UpdateSCMIntegration", + body=maybe_transform( + { + "id": id, + "issuer_url": issuer_url, + "oauth_client_id": oauth_client_id, + "oauth_plaintext_client_secret": oauth_plaintext_client_secret, + "pat": pat, + }, + scm_integration_update_params.ScmIntegrationUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: scm_integration_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: scm_integration_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncIntegrationsPage[ScmIntegration]: + """ + Lists SCM integrations for a runner. + + Use this method to: + + - View all integrations + - Monitor integration status + - Check available SCMs + + ### Examples + + - List integrations: + + Shows all SCM integrations. + + ```yaml + filter: + runnerIds: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing scm integrations + + 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._get_api_list( + "/gitpod.v1.RunnerConfigurationService/ListSCMIntegrations", + page=SyncIntegrationsPage[ScmIntegration], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + scm_integration_list_params.ScmIntegrationListParams, + ), + 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, + }, + scm_integration_list_params.ScmIntegrationListParams, + ), + ), + model=ScmIntegration, + method="post", + ) + + def delete( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes an SCM integration. + + Use this method to: + + - Remove unused integrations + - Clean up configurations + - Revoke SCM access + + ### Examples + + - Delete integration: + + Removes an SCM integration. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerConfigurationService/DeleteSCMIntegration", + body=maybe_transform({"id": id}, scm_integration_delete_params.ScmIntegrationDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncScmIntegrationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncScmIntegrationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncScmIntegrationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncScmIntegrationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncScmIntegrationsResourceWithStreamingResponse(self) + + async def create( + self, + *, + host: str | NotGiven = NOT_GIVEN, + issuer_url: Optional[str] | NotGiven = NOT_GIVEN, + oauth_client_id: Optional[str] | NotGiven = NOT_GIVEN, + oauth_plaintext_client_secret: Optional[str] | NotGiven = NOT_GIVEN, + pat: bool | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + scm_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ScmIntegrationCreateResponse: + """ + Creates a new SCM integration for a runner. + + Use this method to: + + - Configure source control access + - Set up repository integrations + - Enable code synchronization + + ### Examples + + - Create GitHub integration: + + Sets up GitHub SCM integration. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + scmId: "github" + host: "github.com" + oauthClientId: "client_id" + oauthPlaintextClientSecret: "client_secret" + ``` + + Args: + issuer_url: issuer_url can be set to override the authentication provider URL, if it doesn't + match the SCM host. + + oauth_client_id: oauth_client_id is the OAuth app's client ID, if OAuth is configured. If + configured, oauth_plaintext_client_secret must also be set. + + oauth_plaintext_client_secret: oauth_plaintext_client_secret is the OAuth app's client secret in clear text. + This will first be encrypted with the runner's public key before being stored. + + scm_id: scm_id references the scm_id in the runner's configuration schema that this + integration is 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.RunnerConfigurationService/CreateSCMIntegration", + body=await async_maybe_transform( + { + "host": host, + "issuer_url": issuer_url, + "oauth_client_id": oauth_client_id, + "oauth_plaintext_client_secret": oauth_plaintext_client_secret, + "pat": pat, + "runner_id": runner_id, + "scm_id": scm_id, + }, + scm_integration_create_params.ScmIntegrationCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ScmIntegrationCreateResponse, + ) + + async def retrieve( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> ScmIntegrationRetrieveResponse: + """ + Gets details about a specific SCM integration. + + Use this method to: + + - View integration settings + - Check integration status + - Verify configuration + + ### Examples + + - Get integration details: + + Retrieves information about a specific integration. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/GetSCMIntegration", + body=await async_maybe_transform({"id": id}, scm_integration_retrieve_params.ScmIntegrationRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ScmIntegrationRetrieveResponse, + ) + + async def update( + self, + *, + id: str | NotGiven = NOT_GIVEN, + issuer_url: Optional[str] | NotGiven = NOT_GIVEN, + oauth_client_id: Optional[str] | NotGiven = NOT_GIVEN, + oauth_plaintext_client_secret: Optional[str] | NotGiven = NOT_GIVEN, + pat: Optional[bool] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates an existing SCM integration. + + Use this method to: + + - Modify integration settings + - Update credentials + - Change configuration + + ### Examples + + - Update integration: + + Updates OAuth credentials. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + oauthClientId: "new_client_id" + oauthPlaintextClientSecret: "new_client_secret" + ``` + + Args: + issuer_url: issuer_url can be set to override the authentication provider URL, if it doesn't + match the SCM host. + + oauth_client_id: oauth_client_id can be set to update the OAuth app's client ID. If an empty + string is set, the OAuth configuration will be removed (regardless of whether a + client secret is set), and any existing Host Authentication Tokens for the SCM + integration's runner and host that were created using the OAuth app will be + deleted. This might lead to users being unable to access their repositories + until they re-authenticate. + + oauth_plaintext_client_secret: oauth_plaintext_client_secret can be set to update the OAuth app's client + secret. The cleartext secret will be encrypted with the runner's public key + before being stored. + + pat: pat can be set to enable or disable Personal Access Tokens support. When + disabling PATs, any existing Host Authentication Tokens for the SCM + integration's runner and host that were created using a PAT will be deleted. + This might lead to users being unable to access their repositories until they + re-authenticate. + + 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.RunnerConfigurationService/UpdateSCMIntegration", + body=await async_maybe_transform( + { + "id": id, + "issuer_url": issuer_url, + "oauth_client_id": oauth_client_id, + "oauth_plaintext_client_secret": oauth_plaintext_client_secret, + "pat": pat, + }, + scm_integration_update_params.ScmIntegrationUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: scm_integration_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: scm_integration_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[ScmIntegration, AsyncIntegrationsPage[ScmIntegration]]: + """ + Lists SCM integrations for a runner. + + Use this method to: + + - View all integrations + - Monitor integration status + - Check available SCMs + + ### Examples + + - List integrations: + + Shows all SCM integrations. + + ```yaml + filter: + runnerIds: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing scm integrations + + 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._get_api_list( + "/gitpod.v1.RunnerConfigurationService/ListSCMIntegrations", + page=AsyncIntegrationsPage[ScmIntegration], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + scm_integration_list_params.ScmIntegrationListParams, + ), + 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, + }, + scm_integration_list_params.ScmIntegrationListParams, + ), + ), + model=ScmIntegration, + method="post", + ) + + async def delete( + self, + *, + id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes an SCM integration. + + Use this method to: + + - Remove unused integrations + - Clean up configurations + - Revoke SCM access + + ### Examples + + - Delete integration: + + Removes an SCM integration. + + ```yaml + id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerConfigurationService/DeleteSCMIntegration", + body=await async_maybe_transform({"id": id}, scm_integration_delete_params.ScmIntegrationDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class ScmIntegrationsResourceWithRawResponse: + def __init__(self, scm_integrations: ScmIntegrationsResource) -> None: + self._scm_integrations = scm_integrations + + self.create = to_raw_response_wrapper( + scm_integrations.create, + ) + self.retrieve = to_raw_response_wrapper( + scm_integrations.retrieve, + ) + self.update = to_raw_response_wrapper( + scm_integrations.update, + ) + self.list = to_raw_response_wrapper( + scm_integrations.list, + ) + self.delete = to_raw_response_wrapper( + scm_integrations.delete, + ) + + +class AsyncScmIntegrationsResourceWithRawResponse: + def __init__(self, scm_integrations: AsyncScmIntegrationsResource) -> None: + self._scm_integrations = scm_integrations + + self.create = async_to_raw_response_wrapper( + scm_integrations.create, + ) + self.retrieve = async_to_raw_response_wrapper( + scm_integrations.retrieve, + ) + self.update = async_to_raw_response_wrapper( + scm_integrations.update, + ) + self.list = async_to_raw_response_wrapper( + scm_integrations.list, + ) + self.delete = async_to_raw_response_wrapper( + scm_integrations.delete, + ) + + +class ScmIntegrationsResourceWithStreamingResponse: + def __init__(self, scm_integrations: ScmIntegrationsResource) -> None: + self._scm_integrations = scm_integrations + + self.create = to_streamed_response_wrapper( + scm_integrations.create, + ) + self.retrieve = to_streamed_response_wrapper( + scm_integrations.retrieve, + ) + self.update = to_streamed_response_wrapper( + scm_integrations.update, + ) + self.list = to_streamed_response_wrapper( + scm_integrations.list, + ) + self.delete = to_streamed_response_wrapper( + scm_integrations.delete, + ) + + +class AsyncScmIntegrationsResourceWithStreamingResponse: + def __init__(self, scm_integrations: AsyncScmIntegrationsResource) -> None: + self._scm_integrations = scm_integrations + + self.create = async_to_streamed_response_wrapper( + scm_integrations.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + scm_integrations.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + scm_integrations.update, + ) + self.list = async_to_streamed_response_wrapper( + scm_integrations.list, + ) + self.delete = async_to_streamed_response_wrapper( + scm_integrations.delete, + ) diff --git a/src/gitpod/resources/runners/policies.py b/src/gitpod/resources/runners/policies.py new file mode 100644 index 0000000..4ce6cc3 --- /dev/null +++ b/src/gitpod/resources/runners/policies.py @@ -0,0 +1,667 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncPoliciesPage, AsyncPoliciesPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.runners import ( + RunnerRole, + policy_list_params, + policy_create_params, + policy_delete_params, + policy_update_params, +) +from ...types.runners.runner_role import RunnerRole +from ...types.runners.runner_policy import RunnerPolicy +from ...types.runners.policy_create_response import PolicyCreateResponse +from ...types.runners.policy_update_response import PolicyUpdateResponse + +__all__ = ["PoliciesResource", "AsyncPoliciesResource"] + + +class PoliciesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return PoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return PoliciesResourceWithStreamingResponse(self) + + def create( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + role: RunnerRole | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> PolicyCreateResponse: + """ + Creates a new policy for a runner. + + Use this method to: + + - Set up access controls + - Define group permissions + - Configure role-based access + + ### Examples + + - Create admin policy: + + Grants admin access to a group. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: RUNNER_ROLE_ADMIN + ``` + + Args: + group_id: group_id specifies the group_id identifier + + runner_id: runner_id specifies the project identifier + + 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/CreateRunnerPolicy", + body=maybe_transform( + { + "group_id": group_id, + "role": role, + "runner_id": runner_id, + }, + policy_create_params.PolicyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyCreateResponse, + ) + + def update( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + role: RunnerRole | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> PolicyUpdateResponse: + """ + Updates an existing runner policy. + + Use this method to: + + - Modify access levels + - Change group roles + - Update permissions + + ### Examples + + - Update policy role: + + Changes a group's access level. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: RUNNER_ROLE_USER + ``` + + Args: + group_id: group_id specifies the group_id identifier + + runner_id: runner_id specifies the project identifier + + 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/UpdateRunnerPolicy", + body=maybe_transform( + { + "group_id": group_id, + "role": role, + "runner_id": runner_id, + }, + policy_update_params.PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyUpdateResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: policy_list_params.Pagination | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncPoliciesPage[RunnerPolicy]: + """ + Lists policies for a runner. + + Use this method to: + + - View access controls + - Check policy configurations + - Audit permissions + + ### Examples + + - List policies: + + Shows all policies for a runner. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing project policies + + runner_id: runner_id specifies the project identifier + + 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._get_api_list( + "/gitpod.v1.RunnerService/ListRunnerPolicies", + page=SyncPoliciesPage[RunnerPolicy], + body=maybe_transform( + { + "pagination": pagination, + "runner_id": runner_id, + }, + policy_list_params.PolicyListParams, + ), + 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, + }, + policy_list_params.PolicyListParams, + ), + ), + model=RunnerPolicy, + method="post", + ) + + def delete( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a runner policy. + + Use this method to: + + - Remove access controls + - Revoke permissions + - Clean up policies + + ### Examples + + - Delete policy: + + Removes a group's access policy. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + ``` + + Args: + group_id: group_id specifies the group_id identifier + + runner_id: runner_id specifies the project identifier + + 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/DeleteRunnerPolicy", + body=maybe_transform( + { + "group_id": group_id, + "runner_id": runner_id, + }, + policy_delete_params.PolicyDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncPoliciesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncPoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncPoliciesResourceWithStreamingResponse(self) + + async def create( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + role: RunnerRole | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> PolicyCreateResponse: + """ + Creates a new policy for a runner. + + Use this method to: + + - Set up access controls + - Define group permissions + - Configure role-based access + + ### Examples + + - Create admin policy: + + Grants admin access to a group. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: RUNNER_ROLE_ADMIN + ``` + + Args: + group_id: group_id specifies the group_id identifier + + runner_id: runner_id specifies the project identifier + + 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/CreateRunnerPolicy", + body=await async_maybe_transform( + { + "group_id": group_id, + "role": role, + "runner_id": runner_id, + }, + policy_create_params.PolicyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyCreateResponse, + ) + + async def update( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + role: RunnerRole | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> PolicyUpdateResponse: + """ + Updates an existing runner policy. + + Use this method to: + + - Modify access levels + - Change group roles + - Update permissions + + ### Examples + + - Update policy role: + + Changes a group's access level. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + role: RUNNER_ROLE_USER + ``` + + Args: + group_id: group_id specifies the group_id identifier + + runner_id: runner_id specifies the project identifier + + 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/UpdateRunnerPolicy", + body=await async_maybe_transform( + { + "group_id": group_id, + "role": role, + "runner_id": runner_id, + }, + policy_update_params.PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyUpdateResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + pagination: policy_list_params.Pagination | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[RunnerPolicy, AsyncPoliciesPage[RunnerPolicy]]: + """ + Lists policies for a runner. + + Use this method to: + + - View access controls + - Check policy configurations + - Audit permissions + + ### Examples + + - List policies: + + Shows all policies for a runner. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing project policies + + runner_id: runner_id specifies the project identifier + + 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._get_api_list( + "/gitpod.v1.RunnerService/ListRunnerPolicies", + page=AsyncPoliciesPage[RunnerPolicy], + body=maybe_transform( + { + "pagination": pagination, + "runner_id": runner_id, + }, + policy_list_params.PolicyListParams, + ), + 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, + }, + policy_list_params.PolicyListParams, + ), + ), + model=RunnerPolicy, + method="post", + ) + + async def delete( + self, + *, + group_id: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a runner policy. + + Use this method to: + + - Remove access controls + - Revoke permissions + - Clean up policies + + ### Examples + + - Delete policy: + + Removes a group's access policy. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + ``` + + Args: + group_id: group_id specifies the group_id identifier + + runner_id: runner_id specifies the project identifier + + 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/DeleteRunnerPolicy", + body=await async_maybe_transform( + { + "group_id": group_id, + "runner_id": runner_id, + }, + policy_delete_params.PolicyDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class PoliciesResourceWithRawResponse: + def __init__(self, policies: PoliciesResource) -> None: + self._policies = policies + + self.create = to_raw_response_wrapper( + policies.create, + ) + self.update = to_raw_response_wrapper( + policies.update, + ) + self.list = to_raw_response_wrapper( + policies.list, + ) + self.delete = to_raw_response_wrapper( + policies.delete, + ) + + +class AsyncPoliciesResourceWithRawResponse: + def __init__(self, policies: AsyncPoliciesResource) -> None: + self._policies = policies + + self.create = async_to_raw_response_wrapper( + policies.create, + ) + self.update = async_to_raw_response_wrapper( + policies.update, + ) + self.list = async_to_raw_response_wrapper( + policies.list, + ) + self.delete = async_to_raw_response_wrapper( + policies.delete, + ) + + +class PoliciesResourceWithStreamingResponse: + def __init__(self, policies: PoliciesResource) -> None: + self._policies = policies + + self.create = to_streamed_response_wrapper( + policies.create, + ) + self.update = to_streamed_response_wrapper( + policies.update, + ) + self.list = to_streamed_response_wrapper( + policies.list, + ) + self.delete = to_streamed_response_wrapper( + policies.delete, + ) + + +class AsyncPoliciesResourceWithStreamingResponse: + def __init__(self, policies: AsyncPoliciesResource) -> None: + self._policies = policies + + self.create = async_to_streamed_response_wrapper( + policies.create, + ) + self.update = async_to_streamed_response_wrapper( + policies.update, + ) + self.list = async_to_streamed_response_wrapper( + policies.list, + ) + self.delete = async_to_streamed_response_wrapper( + policies.delete, + ) diff --git a/src/gitpod/resources/runners/runners.py b/src/gitpod/resources/runners/runners.py new file mode 100644 index 0000000..876c529 --- /dev/null +++ b/src/gitpod/resources/runners/runners.py @@ -0,0 +1,1327 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ...types import ( + RunnerKind, + RunnerProvider, + runner_list_params, + runner_create_params, + runner_delete_params, + runner_update_params, + runner_retrieve_params, + runner_parse_context_url_params, + runner_create_runner_token_params, + runner_check_authentication_for_host_params, +) +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from .policies import ( + PoliciesResource, + AsyncPoliciesResource, + PoliciesResourceWithRawResponse, + AsyncPoliciesResourceWithRawResponse, + PoliciesResourceWithStreamingResponse, + AsyncPoliciesResourceWithStreamingResponse, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncRunnersPage, AsyncRunnersPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.runner import Runner +from ...types.runner_kind import RunnerKind +from ...types.runner_provider import RunnerProvider +from ...types.runner_spec_param import RunnerSpecParam +from .configurations.configurations import ( + ConfigurationsResource, + AsyncConfigurationsResource, + ConfigurationsResourceWithRawResponse, + AsyncConfigurationsResourceWithRawResponse, + ConfigurationsResourceWithStreamingResponse, + AsyncConfigurationsResourceWithStreamingResponse, +) +from ...types.runner_create_response import RunnerCreateResponse +from ...types.runner_retrieve_response import RunnerRetrieveResponse +from ...types.runner_parse_context_url_response import RunnerParseContextURLResponse +from ...types.runner_create_runner_token_response import RunnerCreateRunnerTokenResponse +from ...types.runner_check_authentication_for_host_response import RunnerCheckAuthenticationForHostResponse + +__all__ = ["RunnersResource", "AsyncRunnersResource"] + + +class RunnersResource(SyncAPIResource): + @cached_property + def configurations(self) -> ConfigurationsResource: + return ConfigurationsResource(self._client) + + @cached_property + def policies(self) -> PoliciesResource: + return PoliciesResource(self._client) + + @cached_property + def with_raw_response(self) -> RunnersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return RunnersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RunnersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return RunnersResourceWithStreamingResponse(self) + + def create( + self, + *, + kind: RunnerKind | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + provider: RunnerProvider | NotGiven = NOT_GIVEN, + runner_manager_id: str | NotGiven = NOT_GIVEN, + spec: RunnerSpecParam | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerCreateResponse: + """Creates a new runner registration with the server. + + Registrations are very + short-lived and must be renewed every 30 seconds. + + Use this method to: + + - Register organization runners + - Set up runner configurations + - Initialize runner credentials + - Configure auto-updates + + ### Examples + + - Create cloud runner: + + Creates a new runner in AWS EC2. + + ```yaml + name: "Production Runner" + provider: RUNNER_PROVIDER_AWS_EC2 + spec: + desiredPhase: RUNNER_PHASE_ACTIVE + configuration: + region: "us-west" + releaseChannel: RUNNER_RELEASE_CHANNEL_STABLE + autoUpdate: true + ``` + + - Create local runner: + + Creates a new local runner on Linux. + + ```yaml + name: "Local Development Runner" + provider: RUNNER_PROVIDER_LINUX_HOST + spec: + desiredPhase: RUNNER_PHASE_ACTIVE + configuration: + releaseChannel: RUNNER_RELEASE_CHANNEL_LATEST + autoUpdate: true + ``` + + Args: + kind: The runner's kind This field is optional and here for backwards-compatibility. + Use the provider field instead. If provider is set, the runner's kind will be + deduced from the provider. Only one of kind and provider must be set. + + name: The runner name for humans + + provider: The specific implementation type of the runner This field is optional for + backwards compatibility but will be required in the future. When specified, kind + must not be specified (will be deduced from provider) + + runner_manager_id: The runner manager id specifies the runner manager for the managed runner. This + field is mandatory for managed runners, otheriwse should not be set. + + 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/CreateRunner", + body=maybe_transform( + { + "kind": kind, + "name": name, + "provider": provider, + "runner_manager_id": runner_manager_id, + "spec": spec, + }, + runner_create_params.RunnerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerCreateResponse, + ) + + def retrieve( + self, + *, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerRetrieveResponse: + """ + Gets details about a specific runner. + + Use this method to: + + - Check runner status + - View runner configuration + - Monitor runner health + - Verify runner capabilities + + ### Examples + + - Get runner details: + + Retrieves information about a specific runner. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerService/GetRunner", + body=maybe_transform({"runner_id": runner_id}, runner_retrieve_params.RunnerRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerRetrieveResponse, + ) + + def update( + self, + *, + name: Optional[str] | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + spec: Optional[runner_update_params.Spec] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates a runner's configuration. + + Use this method to: + + - Modify runner settings + - Update release channels + - Change runner status + - Configure auto-update settings + + ### Examples + + - Update configuration: + + Changes runner settings. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + name: "Updated Runner Name" + spec: + configuration: + releaseChannel: RUNNER_RELEASE_CHANNEL_LATEST + autoUpdate: true + ``` + + Args: + name: The runner's name which is shown to users + + runner_id: runner_id specifies which runner to be updated. + + +required + + 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/UpdateRunner", + body=maybe_transform( + { + "name": name, + "runner_id": runner_id, + "spec": spec, + }, + runner_update_params.RunnerUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: runner_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: runner_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncRunnersPage[Runner]: + """ + Lists all registered runners with optional filtering. + + Use this method to: + + - View all available runners + - Filter by runner type + - Monitor runner status + - Check runner availability + + ### Examples + + - List all runners: + + Shows all runners with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + - Filter by provider: + + Lists only AWS EC2 runners. + + ```yaml + filter: + providers: ["RUNNER_PROVIDER_AWS_EC2"] + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing runners + + 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._get_api_list( + "/gitpod.v1.RunnerService/ListRunners", + page=SyncRunnersPage[Runner], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + runner_list_params.RunnerListParams, + ), + 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_params.RunnerListParams, + ), + ), + model=Runner, + method="post", + ) + + def delete( + self, + *, + force: bool | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a runner permanently. + + Use this method to: + + - Remove unused runners + - Clean up runner registrations + - Delete obsolete runners + + ### Examples + + - Delete runner: + + Permanently removes a runner. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + force: force indicates whether the runner should be deleted forcefully. When force + deleting a Runner, all Environments on the runner are also force deleted and + regular Runner lifecycle is not respected. Force deleting can result in data + loss. + + 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/DeleteRunner", + body=maybe_transform( + { + "force": force, + "runner_id": runner_id, + }, + runner_delete_params.RunnerDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def check_authentication_for_host( + self, + *, + host: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerCheckAuthenticationForHostResponse: + """ + Checks if a user is authenticated for a specific host. + + Use this method to: + + - Verify authentication status + - Get authentication URLs + - Check PAT support + + ### Examples + + - Check authentication: + + Verifies authentication for a host. + + ```yaml + host: "github.com" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerService/CheckAuthenticationForHost", + body=maybe_transform( + { + "host": host, + "runner_id": runner_id, + }, + runner_check_authentication_for_host_params.RunnerCheckAuthenticationForHostParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerCheckAuthenticationForHostResponse, + ) + + def create_runner_token( + self, + *, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerCreateRunnerTokenResponse: + """ + Creates a new authentication token for a runner. + + Use this method to: + + - Generate runner credentials + - Renew expired tokens + - Set up runner authentication + + Note: This does not expire previously issued tokens. + + ### Examples + + - Create token: + + Creates a new token for runner authentication. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerService/CreateRunnerToken", + body=maybe_transform( + {"runner_id": runner_id}, runner_create_runner_token_params.RunnerCreateRunnerTokenParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerCreateRunnerTokenResponse, + ) + + def parse_context_url( + self, + *, + context_url: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerParseContextURLResponse: + """ + Parses a context URL and returns the parsed result. + + Use this method to: + + - Validate context URLs + - Check repository access + - Verify branch existence + + Returns: + + - FAILED_PRECONDITION if authentication is required + - PERMISSION_DENIED if access is not allowed + - INVALID_ARGUMENT if URL is invalid + - NOT_FOUND if repository/branch doesn't exist + + ### Examples + + - Parse URL: + + Parses and validates a context URL. + + ```yaml + contextUrl: "https://github.com/org/repo/tree/main" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.RunnerService/ParseContextURL", + body=maybe_transform( + { + "context_url": context_url, + "runner_id": runner_id, + }, + runner_parse_context_url_params.RunnerParseContextURLParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerParseContextURLResponse, + ) + + +class AsyncRunnersResource(AsyncAPIResource): + @cached_property + def configurations(self) -> AsyncConfigurationsResource: + return AsyncConfigurationsResource(self._client) + + @cached_property + def policies(self) -> AsyncPoliciesResource: + return AsyncPoliciesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncRunnersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncRunnersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRunnersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncRunnersResourceWithStreamingResponse(self) + + async def create( + self, + *, + kind: RunnerKind | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + provider: RunnerProvider | NotGiven = NOT_GIVEN, + runner_manager_id: str | NotGiven = NOT_GIVEN, + spec: RunnerSpecParam | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerCreateResponse: + """Creates a new runner registration with the server. + + Registrations are very + short-lived and must be renewed every 30 seconds. + + Use this method to: + + - Register organization runners + - Set up runner configurations + - Initialize runner credentials + - Configure auto-updates + + ### Examples + + - Create cloud runner: + + Creates a new runner in AWS EC2. + + ```yaml + name: "Production Runner" + provider: RUNNER_PROVIDER_AWS_EC2 + spec: + desiredPhase: RUNNER_PHASE_ACTIVE + configuration: + region: "us-west" + releaseChannel: RUNNER_RELEASE_CHANNEL_STABLE + autoUpdate: true + ``` + + - Create local runner: + + Creates a new local runner on Linux. + + ```yaml + name: "Local Development Runner" + provider: RUNNER_PROVIDER_LINUX_HOST + spec: + desiredPhase: RUNNER_PHASE_ACTIVE + configuration: + releaseChannel: RUNNER_RELEASE_CHANNEL_LATEST + autoUpdate: true + ``` + + Args: + kind: The runner's kind This field is optional and here for backwards-compatibility. + Use the provider field instead. If provider is set, the runner's kind will be + deduced from the provider. Only one of kind and provider must be set. + + name: The runner name for humans + + provider: The specific implementation type of the runner This field is optional for + backwards compatibility but will be required in the future. When specified, kind + must not be specified (will be deduced from provider) + + runner_manager_id: The runner manager id specifies the runner manager for the managed runner. This + field is mandatory for managed runners, otheriwse should not be set. + + 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/CreateRunner", + body=await async_maybe_transform( + { + "kind": kind, + "name": name, + "provider": provider, + "runner_manager_id": runner_manager_id, + "spec": spec, + }, + runner_create_params.RunnerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerCreateResponse, + ) + + async def retrieve( + self, + *, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerRetrieveResponse: + """ + Gets details about a specific runner. + + Use this method to: + + - Check runner status + - View runner configuration + - Monitor runner health + - Verify runner capabilities + + ### Examples + + - Get runner details: + + Retrieves information about a specific runner. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerService/GetRunner", + body=await async_maybe_transform({"runner_id": runner_id}, runner_retrieve_params.RunnerRetrieveParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerRetrieveResponse, + ) + + async def update( + self, + *, + name: Optional[str] | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + spec: Optional[runner_update_params.Spec] | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates a runner's configuration. + + Use this method to: + + - Modify runner settings + - Update release channels + - Change runner status + - Configure auto-update settings + + ### Examples + + - Update configuration: + + Changes runner settings. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + name: "Updated Runner Name" + spec: + configuration: + releaseChannel: RUNNER_RELEASE_CHANNEL_LATEST + autoUpdate: true + ``` + + Args: + name: The runner's name which is shown to users + + runner_id: runner_id specifies which runner to be updated. + + +required + + 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/UpdateRunner", + body=await async_maybe_transform( + { + "name": name, + "runner_id": runner_id, + "spec": spec, + }, + runner_update_params.RunnerUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: runner_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: runner_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Runner, AsyncRunnersPage[Runner]]: + """ + Lists all registered runners with optional filtering. + + Use this method to: + + - View all available runners + - Filter by runner type + - Monitor runner status + - Check runner availability + + ### Examples + + - List all runners: + + Shows all runners with pagination. + + ```yaml + pagination: + pageSize: 20 + ``` + + - Filter by provider: + + Lists only AWS EC2 runners. + + ```yaml + filter: + providers: ["RUNNER_PROVIDER_AWS_EC2"] + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing runners + + 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._get_api_list( + "/gitpod.v1.RunnerService/ListRunners", + page=AsyncRunnersPage[Runner], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + runner_list_params.RunnerListParams, + ), + 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_params.RunnerListParams, + ), + ), + model=Runner, + method="post", + ) + + async def delete( + self, + *, + force: bool | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a runner permanently. + + Use this method to: + + - Remove unused runners + - Clean up runner registrations + - Delete obsolete runners + + ### Examples + + - Delete runner: + + Permanently removes a runner. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + force: force indicates whether the runner should be deleted forcefully. When force + deleting a Runner, all Environments on the runner are also force deleted and + regular Runner lifecycle is not respected. Force deleting can result in data + loss. + + 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/DeleteRunner", + body=await async_maybe_transform( + { + "force": force, + "runner_id": runner_id, + }, + runner_delete_params.RunnerDeleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def check_authentication_for_host( + self, + *, + host: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerCheckAuthenticationForHostResponse: + """ + Checks if a user is authenticated for a specific host. + + Use this method to: + + - Verify authentication status + - Get authentication URLs + - Check PAT support + + ### Examples + + - Check authentication: + + Verifies authentication for a host. + + ```yaml + host: "github.com" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerService/CheckAuthenticationForHost", + body=await async_maybe_transform( + { + "host": host, + "runner_id": runner_id, + }, + runner_check_authentication_for_host_params.RunnerCheckAuthenticationForHostParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerCheckAuthenticationForHostResponse, + ) + + async def create_runner_token( + self, + *, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerCreateRunnerTokenResponse: + """ + Creates a new authentication token for a runner. + + Use this method to: + + - Generate runner credentials + - Renew expired tokens + - Set up runner authentication + + Note: This does not expire previously issued tokens. + + ### Examples + + - Create token: + + Creates a new token for runner authentication. + + ```yaml + runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerService/CreateRunnerToken", + body=await async_maybe_transform( + {"runner_id": runner_id}, runner_create_runner_token_params.RunnerCreateRunnerTokenParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerCreateRunnerTokenResponse, + ) + + async def parse_context_url( + self, + *, + context_url: str | NotGiven = NOT_GIVEN, + runner_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> RunnerParseContextURLResponse: + """ + Parses a context URL and returns the parsed result. + + Use this method to: + + - Validate context URLs + - Check repository access + - Verify branch existence + + Returns: + + - FAILED_PRECONDITION if authentication is required + - PERMISSION_DENIED if access is not allowed + - INVALID_ARGUMENT if URL is invalid + - NOT_FOUND if repository/branch doesn't exist + + ### Examples + + - Parse URL: + + Parses and validates a context URL. + + ```yaml + contextUrl: "https://github.com/org/repo/tree/main" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.RunnerService/ParseContextURL", + body=await async_maybe_transform( + { + "context_url": context_url, + "runner_id": runner_id, + }, + runner_parse_context_url_params.RunnerParseContextURLParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunnerParseContextURLResponse, + ) + + +class RunnersResourceWithRawResponse: + def __init__(self, runners: RunnersResource) -> None: + self._runners = runners + + self.create = to_raw_response_wrapper( + runners.create, + ) + self.retrieve = to_raw_response_wrapper( + runners.retrieve, + ) + self.update = to_raw_response_wrapper( + runners.update, + ) + self.list = to_raw_response_wrapper( + runners.list, + ) + self.delete = to_raw_response_wrapper( + runners.delete, + ) + self.check_authentication_for_host = to_raw_response_wrapper( + runners.check_authentication_for_host, + ) + self.create_runner_token = to_raw_response_wrapper( + runners.create_runner_token, + ) + self.parse_context_url = to_raw_response_wrapper( + runners.parse_context_url, + ) + + @cached_property + def configurations(self) -> ConfigurationsResourceWithRawResponse: + return ConfigurationsResourceWithRawResponse(self._runners.configurations) + + @cached_property + def policies(self) -> PoliciesResourceWithRawResponse: + return PoliciesResourceWithRawResponse(self._runners.policies) + + +class AsyncRunnersResourceWithRawResponse: + def __init__(self, runners: AsyncRunnersResource) -> None: + self._runners = runners + + self.create = async_to_raw_response_wrapper( + runners.create, + ) + self.retrieve = async_to_raw_response_wrapper( + runners.retrieve, + ) + self.update = async_to_raw_response_wrapper( + runners.update, + ) + self.list = async_to_raw_response_wrapper( + runners.list, + ) + self.delete = async_to_raw_response_wrapper( + runners.delete, + ) + self.check_authentication_for_host = async_to_raw_response_wrapper( + runners.check_authentication_for_host, + ) + self.create_runner_token = async_to_raw_response_wrapper( + runners.create_runner_token, + ) + self.parse_context_url = async_to_raw_response_wrapper( + runners.parse_context_url, + ) + + @cached_property + def configurations(self) -> AsyncConfigurationsResourceWithRawResponse: + return AsyncConfigurationsResourceWithRawResponse(self._runners.configurations) + + @cached_property + def policies(self) -> AsyncPoliciesResourceWithRawResponse: + return AsyncPoliciesResourceWithRawResponse(self._runners.policies) + + +class RunnersResourceWithStreamingResponse: + def __init__(self, runners: RunnersResource) -> None: + self._runners = runners + + self.create = to_streamed_response_wrapper( + runners.create, + ) + self.retrieve = to_streamed_response_wrapper( + runners.retrieve, + ) + self.update = to_streamed_response_wrapper( + runners.update, + ) + self.list = to_streamed_response_wrapper( + runners.list, + ) + self.delete = to_streamed_response_wrapper( + runners.delete, + ) + self.check_authentication_for_host = to_streamed_response_wrapper( + runners.check_authentication_for_host, + ) + self.create_runner_token = to_streamed_response_wrapper( + runners.create_runner_token, + ) + self.parse_context_url = to_streamed_response_wrapper( + runners.parse_context_url, + ) + + @cached_property + def configurations(self) -> ConfigurationsResourceWithStreamingResponse: + return ConfigurationsResourceWithStreamingResponse(self._runners.configurations) + + @cached_property + def policies(self) -> PoliciesResourceWithStreamingResponse: + return PoliciesResourceWithStreamingResponse(self._runners.policies) + + +class AsyncRunnersResourceWithStreamingResponse: + def __init__(self, runners: AsyncRunnersResource) -> None: + self._runners = runners + + self.create = async_to_streamed_response_wrapper( + runners.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + runners.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + runners.update, + ) + self.list = async_to_streamed_response_wrapper( + runners.list, + ) + self.delete = async_to_streamed_response_wrapper( + runners.delete, + ) + self.check_authentication_for_host = async_to_streamed_response_wrapper( + runners.check_authentication_for_host, + ) + self.create_runner_token = async_to_streamed_response_wrapper( + runners.create_runner_token, + ) + self.parse_context_url = async_to_streamed_response_wrapper( + runners.parse_context_url, + ) + + @cached_property + def configurations(self) -> AsyncConfigurationsResourceWithStreamingResponse: + return AsyncConfigurationsResourceWithStreamingResponse(self._runners.configurations) + + @cached_property + def policies(self) -> AsyncPoliciesResourceWithStreamingResponse: + return AsyncPoliciesResourceWithStreamingResponse(self._runners.policies) diff --git a/src/gitpod/resources/secrets.py b/src/gitpod/resources/secrets.py new file mode 100644 index 0000000..42c8485 --- /dev/null +++ b/src/gitpod/resources/secrets.py @@ -0,0 +1,855 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import ( + secret_list_params, + secret_create_params, + secret_delete_params, + secret_get_value_params, + secret_update_value_params, +) +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncSecretsPage, AsyncSecretsPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.secret import Secret +from ..types.secret_scope_param import SecretScopeParam +from ..types.secret_create_response import SecretCreateResponse +from ..types.secret_get_value_response import SecretGetValueResponse + +__all__ = ["SecretsResource", "AsyncSecretsResource"] + + +class SecretsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SecretsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return SecretsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SecretsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return SecretsResourceWithStreamingResponse(self) + + def create( + self, + *, + container_registry_basic_auth_host: str | NotGiven = NOT_GIVEN, + environment_variable: bool | NotGiven = NOT_GIVEN, + file_path: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + scope: SecretScopeParam | NotGiven = NOT_GIVEN, + value: str | NotGiven = NOT_GIVEN, + # 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, + ) -> SecretCreateResponse: + """ + Creates a new secret for a project. + + Use this method to: + + - Store sensitive configuration values + - Set up environment variables + - Configure registry authentication + - Add file-based secrets + + ### Examples + + - Create environment variable: + + Creates a secret that will be available as an environment variable. + + ```yaml + name: "DATABASE_URL" + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + value: "postgresql://user:pass@localhost:5432/db" + environmentVariable: true + ``` + + - Create file secret: + + Creates a secret that will be mounted as a file. + + ```yaml + name: "SSH_KEY" + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + value: "-----BEGIN RSA PRIVATE KEY-----\n..." + filePath: "/home/gitpod/.ssh/id_rsa" + ``` + + - Create registry auth: + + Creates credentials for private container registry. + + ```yaml + name: "DOCKER_AUTH" + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + value: "username:password" + containerRegistryBasicAuthHost: "https://registry.example.com" + ``` + + Args: + container_registry_basic_auth_host: secret will be mounted as a docker config in the environment VM, mount will have + the docker registry host + + environment_variable: secret will be created as an Environment Variable with the same name as the + secret + + file_path: absolute path to the file where the secret is mounted value must be an absolute + path (start with a /): + + ``` + this.matches("^/(?:[^/]*/)*.*$") + ``` + + project_id: project_id is the ProjectID this Secret belongs to Deprecated: use scope instead + + scope: scope is the scope of the secret + + value: value is the plaintext value of the secret + + 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.SecretService/CreateSecret", + body=maybe_transform( + { + "container_registry_basic_auth_host": container_registry_basic_auth_host, + "environment_variable": environment_variable, + "file_path": file_path, + "name": name, + "project_id": project_id, + "scope": scope, + "value": value, + }, + secret_create_params.SecretCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecretCreateResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: secret_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: secret_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncSecretsPage[Secret]: + """ + Lists secrets + + Use this method to: + + - View all project secrets + - View all user secrets + + ### Examples + + - List project secrets: + + Shows all secrets for a project. + + ```yaml + filter: + scope: + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + - List user secrets: + + Shows all secrets for a user. + + ```yaml + filter: + scope: + userId: "123e4567-e89b-12d3-a456-426614174000" + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing environments + + 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._get_api_list( + "/gitpod.v1.SecretService/ListSecrets", + page=SyncSecretsPage[Secret], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + secret_list_params.SecretListParams, + ), + 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, + }, + secret_list_params.SecretListParams, + ), + ), + model=Secret, + method="post", + ) + + def delete( + self, + *, + secret_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a secret permanently. + + Use this method to: + + - Remove unused secrets + - Clean up old credentials + + ### Examples + + - Delete secret: + + Permanently removes a secret. + + ```yaml + secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.SecretService/DeleteSecret", + body=maybe_transform({"secret_id": secret_id}, secret_delete_params.SecretDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def get_value( + self, + *, + secret_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> SecretGetValueResponse: + """Gets the value of a secret. + + Only available to environments that are authorized + to access the secret. + + Use this method to: + + - Retrieve secret values + - Access credentials + + ### Examples + + - Get secret value: + + Retrieves the value of a specific secret. + + ```yaml + secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.SecretService/GetSecretValue", + body=maybe_transform({"secret_id": secret_id}, secret_get_value_params.SecretGetValueParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecretGetValueResponse, + ) + + def update_value( + self, + *, + secret_id: str | NotGiven = NOT_GIVEN, + value: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates the value of an existing secret. + + Use this method to: + + - Rotate secret values + - Update credentials + + ### Examples + + - Update secret value: + + Changes the value of an existing secret. + + ```yaml + secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + value: "new-secret-value" + ``` + + Args: + value: value is the plaintext value of the secret + + 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.SecretService/UpdateSecretValue", + body=maybe_transform( + { + "secret_id": secret_id, + "value": value, + }, + secret_update_value_params.SecretUpdateValueParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncSecretsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSecretsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncSecretsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSecretsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncSecretsResourceWithStreamingResponse(self) + + async def create( + self, + *, + container_registry_basic_auth_host: str | NotGiven = NOT_GIVEN, + environment_variable: bool | NotGiven = NOT_GIVEN, + file_path: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + project_id: str | NotGiven = NOT_GIVEN, + scope: SecretScopeParam | NotGiven = NOT_GIVEN, + value: str | NotGiven = NOT_GIVEN, + # 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, + ) -> SecretCreateResponse: + """ + Creates a new secret for a project. + + Use this method to: + + - Store sensitive configuration values + - Set up environment variables + - Configure registry authentication + - Add file-based secrets + + ### Examples + + - Create environment variable: + + Creates a secret that will be available as an environment variable. + + ```yaml + name: "DATABASE_URL" + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + value: "postgresql://user:pass@localhost:5432/db" + environmentVariable: true + ``` + + - Create file secret: + + Creates a secret that will be mounted as a file. + + ```yaml + name: "SSH_KEY" + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + value: "-----BEGIN RSA PRIVATE KEY-----\n..." + filePath: "/home/gitpod/.ssh/id_rsa" + ``` + + - Create registry auth: + + Creates credentials for private container registry. + + ```yaml + name: "DOCKER_AUTH" + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + value: "username:password" + containerRegistryBasicAuthHost: "https://registry.example.com" + ``` + + Args: + container_registry_basic_auth_host: secret will be mounted as a docker config in the environment VM, mount will have + the docker registry host + + environment_variable: secret will be created as an Environment Variable with the same name as the + secret + + file_path: absolute path to the file where the secret is mounted value must be an absolute + path (start with a /): + + ``` + this.matches("^/(?:[^/]*/)*.*$") + ``` + + project_id: project_id is the ProjectID this Secret belongs to Deprecated: use scope instead + + scope: scope is the scope of the secret + + value: value is the plaintext value of the secret + + 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.SecretService/CreateSecret", + body=await async_maybe_transform( + { + "container_registry_basic_auth_host": container_registry_basic_auth_host, + "environment_variable": environment_variable, + "file_path": file_path, + "name": name, + "project_id": project_id, + "scope": scope, + "value": value, + }, + secret_create_params.SecretCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecretCreateResponse, + ) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: secret_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: secret_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[Secret, AsyncSecretsPage[Secret]]: + """ + Lists secrets + + Use this method to: + + - View all project secrets + - View all user secrets + + ### Examples + + - List project secrets: + + Shows all secrets for a project. + + ```yaml + filter: + scope: + projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + pagination: + pageSize: 20 + ``` + + - List user secrets: + + Shows all secrets for a user. + + ```yaml + filter: + scope: + userId: "123e4567-e89b-12d3-a456-426614174000" + pagination: + pageSize: 20 + ``` + + Args: + pagination: pagination contains the pagination options for listing environments + + 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._get_api_list( + "/gitpod.v1.SecretService/ListSecrets", + page=AsyncSecretsPage[Secret], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + secret_list_params.SecretListParams, + ), + 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, + }, + secret_list_params.SecretListParams, + ), + ), + model=Secret, + method="post", + ) + + async def delete( + self, + *, + secret_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a secret permanently. + + Use this method to: + + - Remove unused secrets + - Clean up old credentials + + ### Examples + + - Delete secret: + + Permanently removes a secret. + + ```yaml + secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.SecretService/DeleteSecret", + body=await async_maybe_transform({"secret_id": secret_id}, secret_delete_params.SecretDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def get_value( + self, + *, + secret_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> SecretGetValueResponse: + """Gets the value of a secret. + + Only available to environments that are authorized + to access the secret. + + Use this method to: + + - Retrieve secret values + - Access credentials + + ### Examples + + - Get secret value: + + Retrieves the value of a specific secret. + + ```yaml + secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.SecretService/GetSecretValue", + body=await async_maybe_transform({"secret_id": secret_id}, secret_get_value_params.SecretGetValueParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecretGetValueResponse, + ) + + async def update_value( + self, + *, + secret_id: str | NotGiven = NOT_GIVEN, + value: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Updates the value of an existing secret. + + Use this method to: + + - Rotate secret values + - Update credentials + + ### Examples + + - Update secret value: + + Changes the value of an existing secret. + + ```yaml + secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + value: "new-secret-value" + ``` + + Args: + value: value is the plaintext value of the secret + + 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.SecretService/UpdateSecretValue", + body=await async_maybe_transform( + { + "secret_id": secret_id, + "value": value, + }, + secret_update_value_params.SecretUpdateValueParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class SecretsResourceWithRawResponse: + def __init__(self, secrets: SecretsResource) -> None: + self._secrets = secrets + + self.create = to_raw_response_wrapper( + secrets.create, + ) + self.list = to_raw_response_wrapper( + secrets.list, + ) + self.delete = to_raw_response_wrapper( + secrets.delete, + ) + self.get_value = to_raw_response_wrapper( + secrets.get_value, + ) + self.update_value = to_raw_response_wrapper( + secrets.update_value, + ) + + +class AsyncSecretsResourceWithRawResponse: + def __init__(self, secrets: AsyncSecretsResource) -> None: + self._secrets = secrets + + self.create = async_to_raw_response_wrapper( + secrets.create, + ) + self.list = async_to_raw_response_wrapper( + secrets.list, + ) + self.delete = async_to_raw_response_wrapper( + secrets.delete, + ) + self.get_value = async_to_raw_response_wrapper( + secrets.get_value, + ) + self.update_value = async_to_raw_response_wrapper( + secrets.update_value, + ) + + +class SecretsResourceWithStreamingResponse: + def __init__(self, secrets: SecretsResource) -> None: + self._secrets = secrets + + self.create = to_streamed_response_wrapper( + secrets.create, + ) + self.list = to_streamed_response_wrapper( + secrets.list, + ) + self.delete = to_streamed_response_wrapper( + secrets.delete, + ) + self.get_value = to_streamed_response_wrapper( + secrets.get_value, + ) + self.update_value = to_streamed_response_wrapper( + secrets.update_value, + ) + + +class AsyncSecretsResourceWithStreamingResponse: + def __init__(self, secrets: AsyncSecretsResource) -> None: + self._secrets = secrets + + self.create = async_to_streamed_response_wrapper( + secrets.create, + ) + self.list = async_to_streamed_response_wrapper( + secrets.list, + ) + self.delete = async_to_streamed_response_wrapper( + secrets.delete, + ) + self.get_value = async_to_streamed_response_wrapper( + secrets.get_value, + ) + self.update_value = async_to_streamed_response_wrapper( + secrets.update_value, + ) diff --git a/src/gitpod/resources/usage.py b/src/gitpod/resources/usage.py new file mode 100644 index 0000000..71c698e --- /dev/null +++ b/src/gitpod/resources/usage.py @@ -0,0 +1,258 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import usage_list_environment_runtime_records_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncRecordsPage, AsyncRecordsPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.environment_usage_record import EnvironmentUsageRecord + +__all__ = ["UsageResource", "AsyncUsageResource"] + + +class UsageResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> UsageResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return UsageResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsageResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return UsageResourceWithStreamingResponse(self) + + def list_environment_runtime_records( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: usage_list_environment_runtime_records_params.Filter | NotGiven = NOT_GIVEN, + pagination: usage_list_environment_runtime_records_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncRecordsPage[EnvironmentUsageRecord]: + """ + Lists completed environment runtime records within a specified date range. + + Returns a list of environment runtime records that were completed within the + specified date range. Records of currently running environments are not + included. + + Use this method to: + + - View environment runtime records + - Filter by project + - Create custom usage reports + + ### Example + + ```yaml + filter: + projectId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + dateRange: + startTime: "2024-01-01T00:00:00Z" + endTime: "2024-01-02T00:00:00Z" + pagination: + pageSize: 100 + ``` + + Args: + filter: Filter options. + + pagination: Pagination options. + + 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._get_api_list( + "/gitpod.v1.UsageService/ListEnvironmentUsageRecords", + page=SyncRecordsPage[EnvironmentUsageRecord], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + usage_list_environment_runtime_records_params.UsageListEnvironmentRuntimeRecordsParams, + ), + 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, + }, + usage_list_environment_runtime_records_params.UsageListEnvironmentRuntimeRecordsParams, + ), + ), + model=EnvironmentUsageRecord, + method="post", + ) + + +class AsyncUsageResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncUsageResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsageResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsageResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncUsageResourceWithStreamingResponse(self) + + def list_environment_runtime_records( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: usage_list_environment_runtime_records_params.Filter | NotGiven = NOT_GIVEN, + pagination: usage_list_environment_runtime_records_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[EnvironmentUsageRecord, AsyncRecordsPage[EnvironmentUsageRecord]]: + """ + Lists completed environment runtime records within a specified date range. + + Returns a list of environment runtime records that were completed within the + specified date range. Records of currently running environments are not + included. + + Use this method to: + + - View environment runtime records + - Filter by project + - Create custom usage reports + + ### Example + + ```yaml + filter: + projectId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + dateRange: + startTime: "2024-01-01T00:00:00Z" + endTime: "2024-01-02T00:00:00Z" + pagination: + pageSize: 100 + ``` + + Args: + filter: Filter options. + + pagination: Pagination options. + + 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._get_api_list( + "/gitpod.v1.UsageService/ListEnvironmentUsageRecords", + page=AsyncRecordsPage[EnvironmentUsageRecord], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + usage_list_environment_runtime_records_params.UsageListEnvironmentRuntimeRecordsParams, + ), + 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, + }, + usage_list_environment_runtime_records_params.UsageListEnvironmentRuntimeRecordsParams, + ), + ), + model=EnvironmentUsageRecord, + method="post", + ) + + +class UsageResourceWithRawResponse: + def __init__(self, usage: UsageResource) -> None: + self._usage = usage + + self.list_environment_runtime_records = to_raw_response_wrapper( + usage.list_environment_runtime_records, + ) + + +class AsyncUsageResourceWithRawResponse: + def __init__(self, usage: AsyncUsageResource) -> None: + self._usage = usage + + self.list_environment_runtime_records = async_to_raw_response_wrapper( + usage.list_environment_runtime_records, + ) + + +class UsageResourceWithStreamingResponse: + def __init__(self, usage: UsageResource) -> None: + self._usage = usage + + self.list_environment_runtime_records = to_streamed_response_wrapper( + usage.list_environment_runtime_records, + ) + + +class AsyncUsageResourceWithStreamingResponse: + def __init__(self, usage: AsyncUsageResource) -> None: + self._usage = usage + + self.list_environment_runtime_records = async_to_streamed_response_wrapper( + usage.list_environment_runtime_records, + ) diff --git a/src/gitpod/resources/users/__init__.py b/src/gitpod/resources/users/__init__.py new file mode 100644 index 0000000..7250286 --- /dev/null +++ b/src/gitpod/resources/users/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .pats import ( + PatsResource, + AsyncPatsResource, + PatsResourceWithRawResponse, + AsyncPatsResourceWithRawResponse, + PatsResourceWithStreamingResponse, + AsyncPatsResourceWithStreamingResponse, +) +from .users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from .dotfiles import ( + DotfilesResource, + AsyncDotfilesResource, + DotfilesResourceWithRawResponse, + AsyncDotfilesResourceWithRawResponse, + DotfilesResourceWithStreamingResponse, + AsyncDotfilesResourceWithStreamingResponse, +) + +__all__ = [ + "DotfilesResource", + "AsyncDotfilesResource", + "DotfilesResourceWithRawResponse", + "AsyncDotfilesResourceWithRawResponse", + "DotfilesResourceWithStreamingResponse", + "AsyncDotfilesResourceWithStreamingResponse", + "PatsResource", + "AsyncPatsResource", + "PatsResourceWithRawResponse", + "AsyncPatsResourceWithRawResponse", + "PatsResourceWithStreamingResponse", + "AsyncPatsResourceWithStreamingResponse", + "UsersResource", + "AsyncUsersResource", + "UsersResourceWithRawResponse", + "AsyncUsersResourceWithRawResponse", + "UsersResourceWithStreamingResponse", + "AsyncUsersResourceWithStreamingResponse", +] diff --git a/src/gitpod/resources/users/dotfiles.py b/src/gitpod/resources/users/dotfiles.py new file mode 100644 index 0000000..6e14987 --- /dev/null +++ b/src/gitpod/resources/users/dotfiles.py @@ -0,0 +1,313 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.users import dotfile_get_params, dotfile_set_params +from ..._base_client import make_request_options +from ...types.users.dotfile_get_response import DotfileGetResponse + +__all__ = ["DotfilesResource", "AsyncDotfilesResource"] + + +class DotfilesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DotfilesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return DotfilesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DotfilesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return DotfilesResourceWithStreamingResponse(self) + + def get( + self, + *, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> DotfileGetResponse: + """ + Gets the dotfiles for a user. + + Use this method to: + + - Retrieve user dotfiles + + ### Examples + + - Get dotfiles: + + Retrieves the dotfiles for the current user. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.UserService/GetDotfilesConfiguration", + body=maybe_transform({"empty": empty}, dotfile_get_params.DotfileGetParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DotfileGetResponse, + ) + + def set( + self, + *, + repository: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Sets the dotfiles configuration for a user. + + Use this method to: + + - Configure user dotfiles + - Update dotfiles settings + + ### Examples + + - Set dotfiles configuration: + + Sets the dotfiles configuration for the current user. + + ```yaml + { "repository": "https://github.com/gitpod-io/dotfiles" } + ``` + + - Remove dotfiles: + + Removes the dotfiles for the current user. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.UserService/SetDotfilesConfiguration", + body=maybe_transform({"repository": repository}, dotfile_set_params.DotfileSetParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncDotfilesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDotfilesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncDotfilesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDotfilesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncDotfilesResourceWithStreamingResponse(self) + + async def get( + self, + *, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> DotfileGetResponse: + """ + Gets the dotfiles for a user. + + Use this method to: + + - Retrieve user dotfiles + + ### Examples + + - Get dotfiles: + + Retrieves the dotfiles for the current user. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.UserService/GetDotfilesConfiguration", + body=await async_maybe_transform({"empty": empty}, dotfile_get_params.DotfileGetParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DotfileGetResponse, + ) + + async def set( + self, + *, + repository: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Sets the dotfiles configuration for a user. + + Use this method to: + + - Configure user dotfiles + - Update dotfiles settings + + ### Examples + + - Set dotfiles configuration: + + Sets the dotfiles configuration for the current user. + + ```yaml + { "repository": "https://github.com/gitpod-io/dotfiles" } + ``` + + - Remove dotfiles: + + Removes the dotfiles for the current user. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.UserService/SetDotfilesConfiguration", + body=await async_maybe_transform({"repository": repository}, dotfile_set_params.DotfileSetParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class DotfilesResourceWithRawResponse: + def __init__(self, dotfiles: DotfilesResource) -> None: + self._dotfiles = dotfiles + + self.get = to_raw_response_wrapper( + dotfiles.get, + ) + self.set = to_raw_response_wrapper( + dotfiles.set, + ) + + +class AsyncDotfilesResourceWithRawResponse: + def __init__(self, dotfiles: AsyncDotfilesResource) -> None: + self._dotfiles = dotfiles + + self.get = async_to_raw_response_wrapper( + dotfiles.get, + ) + self.set = async_to_raw_response_wrapper( + dotfiles.set, + ) + + +class DotfilesResourceWithStreamingResponse: + def __init__(self, dotfiles: DotfilesResource) -> None: + self._dotfiles = dotfiles + + self.get = to_streamed_response_wrapper( + dotfiles.get, + ) + self.set = to_streamed_response_wrapper( + dotfiles.set, + ) + + +class AsyncDotfilesResourceWithStreamingResponse: + def __init__(self, dotfiles: AsyncDotfilesResource) -> None: + self._dotfiles = dotfiles + + self.get = async_to_streamed_response_wrapper( + dotfiles.get, + ) + self.set = async_to_streamed_response_wrapper( + dotfiles.set, + ) diff --git a/src/gitpod/resources/users/pats.py b/src/gitpod/resources/users/pats.py new file mode 100644 index 0000000..95511b8 --- /dev/null +++ b/src/gitpod/resources/users/pats.py @@ -0,0 +1,467 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncPersonalAccessTokensPage, AsyncPersonalAccessTokensPage +from ...types.users import pat_get_params, pat_list_params, pat_delete_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.users.pat_get_response import PatGetResponse +from ...types.users.personal_access_token import PersonalAccessToken + +__all__ = ["PatsResource", "AsyncPatsResource"] + + +class PatsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PatsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return PatsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PatsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return PatsResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: pat_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: pat_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> SyncPersonalAccessTokensPage[PersonalAccessToken]: + """ + Lists personal access tokens with optional filtering. + + Use this method to: + + - View all active tokens + - Audit token usage + - Manage token lifecycle + + ### Examples + + - List user tokens: + + Shows all tokens for specific users. + + ```yaml + filter: + userIds: ["f53d2330-3795-4c5d-a1f3-453121af9c60"] + pagination: + pageSize: 20 + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/gitpod.v1.UserService/ListPersonalAccessTokens", + page=SyncPersonalAccessTokensPage[PersonalAccessToken], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + pat_list_params.PatListParams, + ), + 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, + }, + pat_list_params.PatListParams, + ), + ), + model=PersonalAccessToken, + method="post", + ) + + def delete( + self, + *, + personal_access_token_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a personal access token. + + Use this method to: + + - Revoke token access + - Remove unused tokens + - Rotate credentials + + ### Examples + + - Delete token: + + Permanently revokes a token. + + ```yaml + personalAccessTokenId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.UserService/DeletePersonalAccessToken", + body=maybe_transform( + {"personal_access_token_id": personal_access_token_id}, pat_delete_params.PatDeleteParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def get( + self, + *, + personal_access_token_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> PatGetResponse: + """ + Gets details about a specific personal access token. + + Use this method to: + + - View token metadata + - Check token expiration + - Monitor token usage + + ### Examples + + - Get token details: + + Retrieves information about a specific token. + + ```yaml + personalAccessTokenId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.UserService/GetPersonalAccessToken", + body=maybe_transform({"personal_access_token_id": personal_access_token_id}, pat_get_params.PatGetParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PatGetResponse, + ) + + +class AsyncPatsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPatsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncPatsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPatsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncPatsResourceWithStreamingResponse(self) + + def list( + self, + *, + token: str | NotGiven = NOT_GIVEN, + page_size: int | NotGiven = NOT_GIVEN, + filter: pat_list_params.Filter | NotGiven = NOT_GIVEN, + pagination: pat_list_params.Pagination | NotGiven = NOT_GIVEN, + # 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, + ) -> AsyncPaginator[PersonalAccessToken, AsyncPersonalAccessTokensPage[PersonalAccessToken]]: + """ + Lists personal access tokens with optional filtering. + + Use this method to: + + - View all active tokens + - Audit token usage + - Manage token lifecycle + + ### Examples + + - List user tokens: + + Shows all tokens for specific users. + + ```yaml + filter: + userIds: ["f53d2330-3795-4c5d-a1f3-453121af9c60"] + pagination: + pageSize: 20 + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/gitpod.v1.UserService/ListPersonalAccessTokens", + page=AsyncPersonalAccessTokensPage[PersonalAccessToken], + body=maybe_transform( + { + "filter": filter, + "pagination": pagination, + }, + pat_list_params.PatListParams, + ), + 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, + }, + pat_list_params.PatListParams, + ), + ), + model=PersonalAccessToken, + method="post", + ) + + async def delete( + self, + *, + personal_access_token_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Deletes a personal access token. + + Use this method to: + + - Revoke token access + - Remove unused tokens + - Rotate credentials + + ### Examples + + - Delete token: + + Permanently revokes a token. + + ```yaml + personalAccessTokenId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.UserService/DeletePersonalAccessToken", + body=await async_maybe_transform( + {"personal_access_token_id": personal_access_token_id}, pat_delete_params.PatDeleteParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def get( + self, + *, + personal_access_token_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> PatGetResponse: + """ + Gets details about a specific personal access token. + + Use this method to: + + - View token metadata + - Check token expiration + - Monitor token usage + + ### Examples + + - Get token details: + + Retrieves information about a specific token. + + ```yaml + personalAccessTokenId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.UserService/GetPersonalAccessToken", + body=await async_maybe_transform( + {"personal_access_token_id": personal_access_token_id}, pat_get_params.PatGetParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PatGetResponse, + ) + + +class PatsResourceWithRawResponse: + def __init__(self, pats: PatsResource) -> None: + self._pats = pats + + self.list = to_raw_response_wrapper( + pats.list, + ) + self.delete = to_raw_response_wrapper( + pats.delete, + ) + self.get = to_raw_response_wrapper( + pats.get, + ) + + +class AsyncPatsResourceWithRawResponse: + def __init__(self, pats: AsyncPatsResource) -> None: + self._pats = pats + + self.list = async_to_raw_response_wrapper( + pats.list, + ) + self.delete = async_to_raw_response_wrapper( + pats.delete, + ) + self.get = async_to_raw_response_wrapper( + pats.get, + ) + + +class PatsResourceWithStreamingResponse: + def __init__(self, pats: PatsResource) -> None: + self._pats = pats + + self.list = to_streamed_response_wrapper( + pats.list, + ) + self.delete = to_streamed_response_wrapper( + pats.delete, + ) + self.get = to_streamed_response_wrapper( + pats.get, + ) + + +class AsyncPatsResourceWithStreamingResponse: + def __init__(self, pats: AsyncPatsResource) -> None: + self._pats = pats + + self.list = async_to_streamed_response_wrapper( + pats.list, + ) + self.delete = async_to_streamed_response_wrapper( + pats.delete, + ) + self.get = async_to_streamed_response_wrapper( + pats.get, + ) diff --git a/src/gitpod/resources/users/users.py b/src/gitpod/resources/users/users.py new file mode 100644 index 0000000..0ffe276 --- /dev/null +++ b/src/gitpod/resources/users/users.py @@ -0,0 +1,405 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .pats import ( + PatsResource, + AsyncPatsResource, + PatsResourceWithRawResponse, + AsyncPatsResourceWithRawResponse, + PatsResourceWithStreamingResponse, + AsyncPatsResourceWithStreamingResponse, +) +from ...types import user_set_suspended_params, user_get_authenticated_user_params +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from .dotfiles import ( + DotfilesResource, + AsyncDotfilesResource, + DotfilesResourceWithRawResponse, + AsyncDotfilesResourceWithRawResponse, + DotfilesResourceWithStreamingResponse, + AsyncDotfilesResourceWithStreamingResponse, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.user_get_authenticated_user_response import UserGetAuthenticatedUserResponse + +__all__ = ["UsersResource", "AsyncUsersResource"] + + +class UsersResource(SyncAPIResource): + @cached_property + def dotfiles(self) -> DotfilesResource: + return DotfilesResource(self._client) + + @cached_property + def pats(self) -> PatsResource: + return PatsResource(self._client) + + @cached_property + def with_raw_response(self) -> UsersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return UsersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return UsersResourceWithStreamingResponse(self) + + def get_authenticated_user( + self, + *, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> UserGetAuthenticatedUserResponse: + """ + Gets information about the currently authenticated user. + + Use this method to: + + - Get user profile information + - Check authentication status + - Retrieve user settings + - Verify account details + + ### Examples + + - Get current user: + + Retrieves details about the authenticated user. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.UserService/GetAuthenticatedUser", + body=maybe_transform({"empty": empty}, user_get_authenticated_user_params.UserGetAuthenticatedUserParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserGetAuthenticatedUserResponse, + ) + + def set_suspended( + self, + *, + suspended: bool | NotGiven = NOT_GIVEN, + user_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Sets whether a user account is suspended. + + Use this method to: + + - Suspend problematic users + - Reactivate suspended accounts + - Manage user access + + ### Examples + + - Suspend user: + + Suspends a user account. + + ```yaml + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + suspended: true + ``` + + - Reactivate user: + + Removes suspension from a user account. + + ```yaml + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + suspended: false + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/gitpod.v1.UserService/SetSuspended", + body=maybe_transform( + { + "suspended": suspended, + "user_id": user_id, + }, + user_set_suspended_params.UserSetSuspendedParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncUsersResource(AsyncAPIResource): + @cached_property + def dotfiles(self) -> AsyncDotfilesResource: + return AsyncDotfilesResource(self._client) + + @cached_property + def pats(self) -> AsyncPatsResource: + return AsyncPatsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncUsersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/gitpod-io/gitpod-sdk-python#with_streaming_response + """ + return AsyncUsersResourceWithStreamingResponse(self) + + async def get_authenticated_user( + self, + *, + empty: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> UserGetAuthenticatedUserResponse: + """ + Gets information about the currently authenticated user. + + Use this method to: + + - Get user profile information + - Check authentication status + - Retrieve user settings + - Verify account details + + ### Examples + + - Get current user: + + Retrieves details about the authenticated user. + + ```yaml + {} + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.UserService/GetAuthenticatedUser", + body=await async_maybe_transform( + {"empty": empty}, user_get_authenticated_user_params.UserGetAuthenticatedUserParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserGetAuthenticatedUserResponse, + ) + + async def set_suspended( + self, + *, + suspended: bool | NotGiven = NOT_GIVEN, + user_id: str | NotGiven = NOT_GIVEN, + # 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, + ) -> object: + """ + Sets whether a user account is suspended. + + Use this method to: + + - Suspend problematic users + - Reactivate suspended accounts + - Manage user access + + ### Examples + + - Suspend user: + + Suspends a user account. + + ```yaml + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + suspended: true + ``` + + - Reactivate user: + + Removes suspension from a user account. + + ```yaml + userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + suspended: false + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/gitpod.v1.UserService/SetSuspended", + body=await async_maybe_transform( + { + "suspended": suspended, + "user_id": user_id, + }, + user_set_suspended_params.UserSetSuspendedParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class UsersResourceWithRawResponse: + def __init__(self, users: UsersResource) -> None: + self._users = users + + self.get_authenticated_user = to_raw_response_wrapper( + users.get_authenticated_user, + ) + self.set_suspended = to_raw_response_wrapper( + users.set_suspended, + ) + + @cached_property + def dotfiles(self) -> DotfilesResourceWithRawResponse: + return DotfilesResourceWithRawResponse(self._users.dotfiles) + + @cached_property + def pats(self) -> PatsResourceWithRawResponse: + return PatsResourceWithRawResponse(self._users.pats) + + +class AsyncUsersResourceWithRawResponse: + def __init__(self, users: AsyncUsersResource) -> None: + self._users = users + + self.get_authenticated_user = async_to_raw_response_wrapper( + users.get_authenticated_user, + ) + self.set_suspended = async_to_raw_response_wrapper( + users.set_suspended, + ) + + @cached_property + def dotfiles(self) -> AsyncDotfilesResourceWithRawResponse: + return AsyncDotfilesResourceWithRawResponse(self._users.dotfiles) + + @cached_property + def pats(self) -> AsyncPatsResourceWithRawResponse: + return AsyncPatsResourceWithRawResponse(self._users.pats) + + +class UsersResourceWithStreamingResponse: + def __init__(self, users: UsersResource) -> None: + self._users = users + + self.get_authenticated_user = to_streamed_response_wrapper( + users.get_authenticated_user, + ) + self.set_suspended = to_streamed_response_wrapper( + users.set_suspended, + ) + + @cached_property + def dotfiles(self) -> DotfilesResourceWithStreamingResponse: + return DotfilesResourceWithStreamingResponse(self._users.dotfiles) + + @cached_property + def pats(self) -> PatsResourceWithStreamingResponse: + return PatsResourceWithStreamingResponse(self._users.pats) + + +class AsyncUsersResourceWithStreamingResponse: + def __init__(self, users: AsyncUsersResource) -> None: + self._users = users + + self.get_authenticated_user = async_to_streamed_response_wrapper( + users.get_authenticated_user, + ) + self.set_suspended = async_to_streamed_response_wrapper( + users.set_suspended, + ) + + @cached_property + def dotfiles(self) -> AsyncDotfilesResourceWithStreamingResponse: + return AsyncDotfilesResourceWithStreamingResponse(self._users.dotfiles) + + @cached_property + def pats(self) -> AsyncPatsResourceWithStreamingResponse: + return AsyncPatsResourceWithStreamingResponse(self._users.pats) diff --git a/src/gitpod/types/__init__.py b/src/gitpod/types/__init__.py new file mode 100644 index 0000000..cfa1c5d --- /dev/null +++ b/src/gitpod/types/__init__.py @@ -0,0 +1,189 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .user import User as User +from .group import Group as Group +from .editor import Editor as Editor +from .runner import Runner as Runner +from .secret import Secret as Secret +from .shared import ( + Task as Task, + RunsOn as RunsOn, + Gateway as Gateway, + Subject as Subject, + TaskSpec as TaskSpec, + ErrorCode as ErrorCode, + Principal as Principal, + FieldValue as FieldValue, + UserStatus as UserStatus, + TaskMetadata as TaskMetadata, + TaskExecution as TaskExecution, + EnvironmentClass as EnvironmentClass, + OrganizationRole as OrganizationRole, + AutomationTrigger as AutomationTrigger, + TaskExecutionSpec as TaskExecutionSpec, + TaskExecutionPhase as TaskExecutionPhase, + TaskExecutionStatus as TaskExecutionStatus, + TaskExecutionMetadata as TaskExecutionMetadata, +) +from .account import Account as Account +from .project import Project as Project +from .log_level import LogLevel as LogLevel +from .environment import Environment as Environment +from .runner_kind import RunnerKind as RunnerKind +from .runner_spec import RunnerSpec as RunnerSpec +from .gateway_info import GatewayInfo as GatewayInfo +from .organization import Organization as Organization +from .runner_phase import RunnerPhase as RunnerPhase +from .secret_scope import SecretScope as SecretScope +from .resource_type import ResourceType as ResourceType +from .runner_status import RunnerStatus as RunnerStatus +from .invite_domains import InviteDomains as InviteDomains +from .login_provider import LoginProvider as LoginProvider +from .admission_level import AdmissionLevel as AdmissionLevel +from .runner_provider import RunnerProvider as RunnerProvider +from .environment_spec import EnvironmentSpec as EnvironmentSpec +from .id_token_version import IDTokenVersion as IDTokenVersion +from .project_metadata import ProjectMetadata as ProjectMetadata +from .environment_phase import EnvironmentPhase as EnvironmentPhase +from .event_list_params import EventListParams as EventListParams +from .group_list_params import GroupListParams as GroupListParams +from .organization_tier import OrganizationTier as OrganizationTier +from .runner_capability import RunnerCapability as RunnerCapability +from .runner_spec_param import RunnerSpecParam as RunnerSpecParam +from .account_membership import AccountMembership as AccountMembership +from .editor_list_params import EditorListParams as EditorListParams +from .environment_status import EnvironmentStatus as EnvironmentStatus +from .event_watch_params import EventWatchParams as EventWatchParams +from .resource_operation import ResourceOperation as ResourceOperation +from .runner_list_params import RunnerListParams as RunnerListParams +from .secret_list_params import SecretListParams as SecretListParams +from .secret_scope_param import SecretScopeParam as SecretScopeParam +from .event_list_response import EventListResponse as EventListResponse +from .gateway_list_params import GatewayListParams as GatewayListParams +from .organization_member import OrganizationMember as OrganizationMember +from .project_list_params import ProjectListParams as ProjectListParams +from .environment_metadata import EnvironmentMetadata as EnvironmentMetadata +from .event_watch_response import EventWatchResponse as EventWatchResponse +from .invite_domains_param import InviteDomainsParam as InviteDomainsParam +from .runner_configuration import RunnerConfiguration as RunnerConfiguration +from .runner_create_params import RunnerCreateParams as RunnerCreateParams +from .runner_delete_params import RunnerDeleteParams as RunnerDeleteParams +from .runner_update_params import RunnerUpdateParams as RunnerUpdateParams +from .secret_create_params import SecretCreateParams as SecretCreateParams +from .secret_delete_params import SecretDeleteParams as SecretDeleteParams +from .account_delete_params import AccountDeleteParams as AccountDeleteParams +from .joinable_organization import JoinableOrganization as JoinableOrganization +from .metrics_configuration import MetricsConfiguration as MetricsConfiguration +from .project_create_params import ProjectCreateParams as ProjectCreateParams +from .project_delete_params import ProjectDeleteParams as ProjectDeleteParams +from .project_update_params import ProjectUpdateParams as ProjectUpdateParams +from .editor_retrieve_params import EditorRetrieveParams as EditorRetrieveParams +from .environment_spec_param import EnvironmentSpecParam as EnvironmentSpecParam +from .runner_create_response import RunnerCreateResponse as RunnerCreateResponse +from .runner_release_channel import RunnerReleaseChannel as RunnerReleaseChannel +from .runner_retrieve_params import RunnerRetrieveParams as RunnerRetrieveParams +from .secret_create_response import SecretCreateResponse as SecretCreateResponse +from .account_retrieve_params import AccountRetrieveParams as AccountRetrieveParams +from .environment_initializer import EnvironmentInitializer as EnvironmentInitializer +from .environment_list_params import EnvironmentListParams as EnvironmentListParams +from .environment_stop_params import EnvironmentStopParams as EnvironmentStopParams +from .project_create_response import ProjectCreateResponse as ProjectCreateResponse +from .project_retrieve_params import ProjectRetrieveParams as ProjectRetrieveParams +from .project_update_response import ProjectUpdateResponse as ProjectUpdateResponse +from .secret_get_value_params import SecretGetValueParams as SecretGetValueParams +from .editor_retrieve_response import EditorRetrieveResponse as EditorRetrieveResponse +from .environment_start_params import EnvironmentStartParams as EnvironmentStartParams +from .environment_usage_record import EnvironmentUsageRecord as EnvironmentUsageRecord +from .organization_join_params import OrganizationJoinParams as OrganizationJoinParams +from .runner_retrieve_response import RunnerRetrieveResponse as RunnerRetrieveResponse +from .account_retrieve_response import AccountRetrieveResponse as AccountRetrieveResponse +from .editor_resolve_url_params import EditorResolveURLParams as EditorResolveURLParams +from .environment_create_params import EnvironmentCreateParams as EnvironmentCreateParams +from .environment_delete_params import EnvironmentDeleteParams as EnvironmentDeleteParams +from .environment_update_params import EnvironmentUpdateParams as EnvironmentUpdateParams +from .organization_leave_params import OrganizationLeaveParams as OrganizationLeaveParams +from .project_environment_class import ProjectEnvironmentClass as ProjectEnvironmentClass +from .project_retrieve_response import ProjectRetrieveResponse as ProjectRetrieveResponse +from .secret_get_value_response import SecretGetValueResponse as SecretGetValueResponse +from .user_set_suspended_params import UserSetSuspendedParams as UserSetSuspendedParams +from .organization_create_params import OrganizationCreateParams as OrganizationCreateParams +from .organization_delete_params import OrganizationDeleteParams as OrganizationDeleteParams +from .organization_join_response import OrganizationJoinResponse as OrganizationJoinResponse +from .organization_update_params import OrganizationUpdateParams as OrganizationUpdateParams +from .runner_configuration_param import RunnerConfigurationParam as RunnerConfigurationParam +from .secret_update_value_params import SecretUpdateValueParams as SecretUpdateValueParams +from .editor_resolve_url_response import EditorResolveURLResponse as EditorResolveURLResponse +from .environment_activity_signal import EnvironmentActivitySignal as EnvironmentActivitySignal +from .environment_create_response import EnvironmentCreateResponse as EnvironmentCreateResponse +from .environment_retrieve_params import EnvironmentRetrieveParams as EnvironmentRetrieveParams +from .metrics_configuration_param import MetricsConfigurationParam as MetricsConfigurationParam +from .environment_unarchive_params import EnvironmentUnarchiveParams as EnvironmentUnarchiveParams +from .identity_get_id_token_params import IdentityGetIDTokenParams as IdentityGetIDTokenParams +from .organization_create_response import OrganizationCreateResponse as OrganizationCreateResponse +from .organization_retrieve_params import OrganizationRetrieveParams as OrganizationRetrieveParams +from .organization_set_role_params import OrganizationSetRoleParams as OrganizationSetRoleParams +from .organization_update_response import OrganizationUpdateResponse as OrganizationUpdateResponse +from .environment_initializer_param import EnvironmentInitializerParam as EnvironmentInitializerParam +from .environment_retrieve_response import EnvironmentRetrieveResponse as EnvironmentRetrieveResponse +from .environment_mark_active_params import EnvironmentMarkActiveParams as EnvironmentMarkActiveParams +from .identity_exchange_token_params import IdentityExchangeTokenParams as IdentityExchangeTokenParams +from .identity_get_id_token_response import IdentityGetIDTokenResponse as IdentityGetIDTokenResponse +from .organization_retrieve_response import OrganizationRetrieveResponse as OrganizationRetrieveResponse +from .project_environment_class_param import ProjectEnvironmentClassParam as ProjectEnvironmentClassParam +from .runner_parse_context_url_params import RunnerParseContextURLParams as RunnerParseContextURLParams +from .account_get_sso_login_url_params import AccountGetSSOLoginURLParams as AccountGetSSOLoginURLParams +from .identity_exchange_token_response import IdentityExchangeTokenResponse as IdentityExchangeTokenResponse +from .organization_list_members_params import OrganizationListMembersParams as OrganizationListMembersParams +from .environment_activity_signal_param import EnvironmentActivitySignalParam as EnvironmentActivitySignalParam +from .runner_create_runner_token_params import RunnerCreateRunnerTokenParams as RunnerCreateRunnerTokenParams +from .runner_parse_context_url_response import RunnerParseContextURLResponse as RunnerParseContextURLResponse +from .account_get_sso_login_url_response import AccountGetSSOLoginURLResponse as AccountGetSSOLoginURLResponse +from .user_get_authenticated_user_params import UserGetAuthenticatedUserParams as UserGetAuthenticatedUserParams +from .account_list_login_providers_params import AccountListLoginProvidersParams as AccountListLoginProvidersParams +from .runner_create_runner_token_response import RunnerCreateRunnerTokenResponse as RunnerCreateRunnerTokenResponse +from .environment_create_logs_token_params import EnvironmentCreateLogsTokenParams as EnvironmentCreateLogsTokenParams +from .user_get_authenticated_user_response import UserGetAuthenticatedUserResponse as UserGetAuthenticatedUserResponse +from .environment_create_from_project_params import ( + EnvironmentCreateFromProjectParams as EnvironmentCreateFromProjectParams, +) +from .environment_create_logs_token_response import ( + EnvironmentCreateLogsTokenResponse as EnvironmentCreateLogsTokenResponse, +) +from .project_create_from_environment_params import ( + ProjectCreateFromEnvironmentParams as ProjectCreateFromEnvironmentParams, +) +from .environment_create_from_project_response import ( + EnvironmentCreateFromProjectResponse as EnvironmentCreateFromProjectResponse, +) +from .project_create_from_environment_response import ( + ProjectCreateFromEnvironmentResponse as ProjectCreateFromEnvironmentResponse, +) +from .account_list_joinable_organizations_params import ( + AccountListJoinableOrganizationsParams as AccountListJoinableOrganizationsParams, +) +from .identity_get_authenticated_identity_params import ( + IdentityGetAuthenticatedIdentityParams as IdentityGetAuthenticatedIdentityParams, +) +from .environment_create_environment_token_params import ( + EnvironmentCreateEnvironmentTokenParams as EnvironmentCreateEnvironmentTokenParams, +) +from .runner_check_authentication_for_host_params import ( + RunnerCheckAuthenticationForHostParams as RunnerCheckAuthenticationForHostParams, +) +from .account_list_joinable_organizations_response import ( + AccountListJoinableOrganizationsResponse as AccountListJoinableOrganizationsResponse, +) +from .identity_get_authenticated_identity_response import ( + IdentityGetAuthenticatedIdentityResponse as IdentityGetAuthenticatedIdentityResponse, +) +from .environment_create_environment_token_response import ( + EnvironmentCreateEnvironmentTokenResponse as EnvironmentCreateEnvironmentTokenResponse, +) +from .runner_check_authentication_for_host_response import ( + RunnerCheckAuthenticationForHostResponse as RunnerCheckAuthenticationForHostResponse, +) +from .usage_list_environment_runtime_records_params import ( + UsageListEnvironmentRuntimeRecordsParams as UsageListEnvironmentRuntimeRecordsParams, +) diff --git a/src/gitpod/types/account.py b/src/gitpod/types/account.py new file mode 100644 index 0000000..41ee046 --- /dev/null +++ b/src/gitpod/types/account.py @@ -0,0 +1,223 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .account_membership import AccountMembership +from .joinable_organization import JoinableOrganization + +__all__ = ["Account"] + + +class Account(BaseModel): + id: str + + created_at: datetime = FieldInfo(alias="createdAt") + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + email: str + + name: str + + updated_at: datetime = FieldInfo(alias="updatedAt") + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + avatar_url: Optional[str] = FieldInfo(alias="avatarUrl", default=None) + + joinables: Optional[List[JoinableOrganization]] = None + """joinables is deprecated. Use ListJoinableOrganizations instead.""" + + memberships: Optional[List[AccountMembership]] = None + + organization_id: Optional[str] = FieldInfo(alias="organizationId", default=None) + """ + organization_id is the ID of the organization the account is owned by if it's + created through custom SSO + """ + + public_email_provider: Optional[bool] = FieldInfo(alias="publicEmailProvider", default=None) + """ + public_email_provider is true if the email for the Account matches a known + public email provider + """ diff --git a/src/gitpod/types/account_delete_params.py b/src/gitpod/types/account_delete_params.py new file mode 100644 index 0000000..a049132 --- /dev/null +++ b/src/gitpod/types/account_delete_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["AccountDeleteParams"] + + +class AccountDeleteParams(TypedDict, total=False): + account_id: Required[Annotated[str, PropertyInfo(alias="accountId")]] diff --git a/src/gitpod/types/account_get_sso_login_url_params.py b/src/gitpod/types/account_get_sso_login_url_params.py new file mode 100644 index 0000000..4551e59 --- /dev/null +++ b/src/gitpod/types/account_get_sso_login_url_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["AccountGetSSOLoginURLParams"] + + +class AccountGetSSOLoginURLParams(TypedDict, total=False): + email: Required[str] + """email is the email the user wants to login with""" + + return_to: Annotated[Optional[str], PropertyInfo(alias="returnTo")] + """return_to is the URL the user will be redirected to after login""" diff --git a/src/gitpod/types/account_get_sso_login_url_response.py b/src/gitpod/types/account_get_sso_login_url_response.py new file mode 100644 index 0000000..fd289cd --- /dev/null +++ b/src/gitpod/types/account_get_sso_login_url_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["AccountGetSSOLoginURLResponse"] + + +class AccountGetSSOLoginURLResponse(BaseModel): + login_url: str = FieldInfo(alias="loginUrl") + """login_url is the URL to redirect the user to for SSO login""" diff --git a/src/gitpod/types/account_list_joinable_organizations_params.py b/src/gitpod/types/account_list_joinable_organizations_params.py new file mode 100644 index 0000000..d4531fb --- /dev/null +++ b/src/gitpod/types/account_list_joinable_organizations_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 Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["AccountListJoinableOrganizationsParams"] + + +class AccountListJoinableOrganizationsParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + empty: bool diff --git a/src/gitpod/types/account_list_joinable_organizations_response.py b/src/gitpod/types/account_list_joinable_organizations_response.py new file mode 100644 index 0000000..3253ba5 --- /dev/null +++ b/src/gitpod/types/account_list_joinable_organizations_response.py @@ -0,0 +1,16 @@ +# 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 +from .joinable_organization import JoinableOrganization + +__all__ = ["AccountListJoinableOrganizationsResponse"] + + +class AccountListJoinableOrganizationsResponse(BaseModel): + joinable_organizations: Optional[List[JoinableOrganization]] = FieldInfo( + alias="joinableOrganizations", default=None + ) diff --git a/src/gitpod/types/account_list_login_providers_params.py b/src/gitpod/types/account_list_login_providers_params.py new file mode 100644 index 0000000..e7c5da7 --- /dev/null +++ b/src/gitpod/types/account_list_login_providers_params.py @@ -0,0 +1,40 @@ +# 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__ = ["AccountListLoginProvidersParams", "Filter", "Pagination"] + + +class AccountListLoginProvidersParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + """filter contains the filter options for listing login methods""" + + pagination: Pagination + """pagination contains the pagination options for listing login methods""" + + +class Filter(TypedDict, total=False): + invite_id: Annotated[str, PropertyInfo(alias="inviteId")] + """invite_id is the ID of the invite URL the user wants to login with""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/account_membership.py b/src/gitpod/types/account_membership.py new file mode 100644 index 0000000..10f2603 --- /dev/null +++ b/src/gitpod/types/account_membership.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.organization_role import OrganizationRole + +__all__ = ["AccountMembership"] + + +class AccountMembership(BaseModel): + organization_id: str = FieldInfo(alias="organizationId") + """organization_id is the id of the organization the user is a member of""" + + organization_name: str = FieldInfo(alias="organizationName") + """organization_name is the name of the organization the user is a member of""" + + user_id: str = FieldInfo(alias="userId") + """user_id is the ID the user has in the organization""" + + user_role: OrganizationRole = FieldInfo(alias="userRole") + """user_role is the role the user has in the organization""" + + 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 + """ diff --git a/src/gitpod/types/account_retrieve_params.py b/src/gitpod/types/account_retrieve_params.py new file mode 100644 index 0000000..68642eb --- /dev/null +++ b/src/gitpod/types/account_retrieve_params.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 TypedDict + +__all__ = ["AccountRetrieveParams"] + + +class AccountRetrieveParams(TypedDict, total=False): + empty: bool diff --git a/src/gitpod/types/account_retrieve_response.py b/src/gitpod/types/account_retrieve_response.py new file mode 100644 index 0000000..c32afbb --- /dev/null +++ b/src/gitpod/types/account_retrieve_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .account import Account +from .._models import BaseModel + +__all__ = ["AccountRetrieveResponse"] + + +class AccountRetrieveResponse(BaseModel): + account: Account diff --git a/src/gitpod/types/admission_level.py b/src/gitpod/types/admission_level.py new file mode 100644 index 0000000..40ee48d --- /dev/null +++ b/src/gitpod/types/admission_level.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["AdmissionLevel"] + +AdmissionLevel: TypeAlias = Literal[ + "ADMISSION_LEVEL_UNSPECIFIED", "ADMISSION_LEVEL_OWNER_ONLY", "ADMISSION_LEVEL_EVERYONE" +] diff --git a/src/gitpod/types/editor.py b/src/gitpod/types/editor.py new file mode 100644 index 0000000..96eebfa --- /dev/null +++ b/src/gitpod/types/editor.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["Editor"] + + +class Editor(BaseModel): + id: str + + installation_instructions: str = FieldInfo(alias="installationInstructions") + + name: str + + url_template: str = FieldInfo(alias="urlTemplate") + + alias: Optional[str] = None + + icon_url: Optional[str] = FieldInfo(alias="iconUrl", default=None) + + short_description: Optional[str] = FieldInfo(alias="shortDescription", default=None) diff --git a/src/gitpod/types/editor_list_params.py b/src/gitpod/types/editor_list_params.py new file mode 100644 index 0000000..42f9426 --- /dev/null +++ b/src/gitpod/types/editor_list_params.py @@ -0,0 +1,43 @@ +# 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__ = ["EditorListParams", "Filter", "Pagination"] + + +class EditorListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + """filter contains the filter options for listing editors""" + + pagination: Pagination + """pagination contains the pagination options for listing environments""" + + +class Filter(TypedDict, total=False): + allowed_by_policy: Annotated[bool, PropertyInfo(alias="allowedByPolicy")] + """ + allowed_by_policy filters the response to only editors that are allowed by the + policies enforced in the organization + """ + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/editor_resolve_url_params.py b/src/gitpod/types/editor_resolve_url_params.py new file mode 100644 index 0000000..de698ba --- /dev/null +++ b/src/gitpod/types/editor_resolve_url_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 Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EditorResolveURLParams"] + + +class EditorResolveURLParams(TypedDict, total=False): + editor_id: Required[Annotated[str, PropertyInfo(alias="editorId")]] + """editorId is the ID of the editor to resolve the URL for""" + + environment_id: Required[Annotated[str, PropertyInfo(alias="environmentId")]] + """environmentId is the ID of the environment to resolve the URL for""" + + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + """organizationId is the ID of the organization to resolve the URL for""" diff --git a/src/gitpod/types/editor_resolve_url_response.py b/src/gitpod/types/editor_resolve_url_response.py new file mode 100644 index 0000000..9633464 --- /dev/null +++ b/src/gitpod/types/editor_resolve_url_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["EditorResolveURLResponse"] + + +class EditorResolveURLResponse(BaseModel): + url: str + """url is the resolved editor URL""" diff --git a/src/gitpod/types/editor_retrieve_params.py b/src/gitpod/types/editor_retrieve_params.py new file mode 100644 index 0000000..f9f5194 --- /dev/null +++ b/src/gitpod/types/editor_retrieve_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["EditorRetrieveParams"] + + +class EditorRetrieveParams(TypedDict, total=False): + id: Required[str] + """id is the ID of the editor to get""" diff --git a/src/gitpod/types/editor_retrieve_response.py b/src/gitpod/types/editor_retrieve_response.py new file mode 100644 index 0000000..0a40810 --- /dev/null +++ b/src/gitpod/types/editor_retrieve_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .editor import Editor +from .._models import BaseModel + +__all__ = ["EditorRetrieveResponse"] + + +class EditorRetrieveResponse(BaseModel): + editor: Editor + """editor contains the editor""" diff --git a/src/gitpod/types/environment.py b/src/gitpod/types/environment.py new file mode 100644 index 0000000..560cf25 --- /dev/null +++ b/src/gitpod/types/environment.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel +from .environment_spec import EnvironmentSpec +from .environment_status import EnvironmentStatus +from .environment_metadata import EnvironmentMetadata + +__all__ = ["Environment"] + + +class Environment(BaseModel): + id: str + """ID is a unique identifier of this environment. + + No other environment with the same name must be managed by this environment + manager + """ + + metadata: Optional[EnvironmentMetadata] = None + """ + Metadata is data associated with this environment that's required for other + parts of Gitpod to function + """ + + spec: Optional[EnvironmentSpec] = None + """ + Spec is the configuration of the environment that's required for the runner to + start the environment + """ + + status: Optional[EnvironmentStatus] = None + """Status is the current status of the environment""" diff --git a/src/gitpod/types/environment_activity_signal.py b/src/gitpod/types/environment_activity_signal.py new file mode 100644 index 0000000..afedc99 --- /dev/null +++ b/src/gitpod/types/environment_activity_signal.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from .._models import BaseModel + +__all__ = ["EnvironmentActivitySignal"] + + +class EnvironmentActivitySignal(BaseModel): + source: Optional[str] = None + """ + source of the activity signal, such as "VS Code", "SSH", or "Automations". It + should be a human-readable string that describes the source of the activity + signal. + """ + + timestamp: Optional[datetime] = None + """ + timestamp of when the activity was observed by the source. Only reported every 5 + minutes. Zero value means no activity was observed. + """ diff --git a/src/gitpod/types/environment_activity_signal_param.py b/src/gitpod/types/environment_activity_signal_param.py new file mode 100644 index 0000000..a9cb0c1 --- /dev/null +++ b/src/gitpod/types/environment_activity_signal_param.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EnvironmentActivitySignalParam"] + + +class EnvironmentActivitySignalParam(TypedDict, total=False): + source: str + """ + source of the activity signal, such as "VS Code", "SSH", or "Automations". It + should be a human-readable string that describes the source of the activity + signal. + """ + + timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ + timestamp of when the activity was observed by the source. Only reported every 5 + minutes. Zero value means no activity was observed. + """ diff --git a/src/gitpod/types/environment_create_environment_token_params.py b/src/gitpod/types/environment_create_environment_token_params.py new file mode 100644 index 0000000..cf7fdd1 --- /dev/null +++ b/src/gitpod/types/environment_create_environment_token_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 + +__all__ = ["EnvironmentCreateEnvironmentTokenParams"] + + +class EnvironmentCreateEnvironmentTokenParams(TypedDict, total=False): + environment_id: Required[Annotated[str, PropertyInfo(alias="environmentId")]] + """ + environment_id specifies the environment for which the access token should be + created. + """ diff --git a/src/gitpod/types/environment_create_environment_token_response.py b/src/gitpod/types/environment_create_environment_token_response.py new file mode 100644 index 0000000..64b74d7 --- /dev/null +++ b/src/gitpod/types/environment_create_environment_token_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EnvironmentCreateEnvironmentTokenResponse"] + + +class EnvironmentCreateEnvironmentTokenResponse(BaseModel): + access_token: str = FieldInfo(alias="accessToken") + """access_token is the token that can be used for environment authentication""" diff --git a/src/gitpod/types/environment_create_from_project_params.py b/src/gitpod/types/environment_create_from_project_params.py new file mode 100644 index 0000000..2c9806f --- /dev/null +++ b/src/gitpod/types/environment_create_from_project_params.py @@ -0,0 +1,21 @@ +# 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 +from .environment_spec_param import EnvironmentSpecParam + +__all__ = ["EnvironmentCreateFromProjectParams"] + + +class EnvironmentCreateFromProjectParams(TypedDict, total=False): + project_id: Annotated[str, PropertyInfo(alias="projectId")] + + spec: EnvironmentSpecParam + """ + Spec is the configuration of the environment that's required for the runner to + start the environment Configuration already defined in the Project will override + parts of the spec, if set + """ diff --git a/src/gitpod/types/environment_create_from_project_response.py b/src/gitpod/types/environment_create_from_project_response.py new file mode 100644 index 0000000..3390ce0 --- /dev/null +++ b/src/gitpod/types/environment_create_from_project_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .environment import Environment + +__all__ = ["EnvironmentCreateFromProjectResponse"] + + +class EnvironmentCreateFromProjectResponse(BaseModel): + environment: Environment + """+resource get environment""" diff --git a/src/gitpod/types/environment_create_logs_token_params.py b/src/gitpod/types/environment_create_logs_token_params.py new file mode 100644 index 0000000..ba9f17e --- /dev/null +++ b/src/gitpod/types/environment_create_logs_token_params.py @@ -0,0 +1,19 @@ +# 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__ = ["EnvironmentCreateLogsTokenParams"] + + +class EnvironmentCreateLogsTokenParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """ + environment_id specifies the environment for which the logs token should be + created. + + +required + """ diff --git a/src/gitpod/types/environment_create_logs_token_response.py b/src/gitpod/types/environment_create_logs_token_response.py new file mode 100644 index 0000000..c8a81b7 --- /dev/null +++ b/src/gitpod/types/environment_create_logs_token_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EnvironmentCreateLogsTokenResponse"] + + +class EnvironmentCreateLogsTokenResponse(BaseModel): + access_token: str = FieldInfo(alias="accessToken") + """ + access_token is the token that can be used to access the logs of the environment + """ diff --git a/src/gitpod/types/environment_create_params.py b/src/gitpod/types/environment_create_params.py new file mode 100644 index 0000000..e49a7d2 --- /dev/null +++ b/src/gitpod/types/environment_create_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 TypedDict + +from .environment_spec_param import EnvironmentSpecParam + +__all__ = ["EnvironmentCreateParams"] + + +class EnvironmentCreateParams(TypedDict, total=False): + spec: EnvironmentSpecParam + """ + spec is the configuration of the environment that's required for the to start + the environment + """ diff --git a/src/gitpod/types/environment_create_response.py b/src/gitpod/types/environment_create_response.py new file mode 100644 index 0000000..e3c53f0 --- /dev/null +++ b/src/gitpod/types/environment_create_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .environment import Environment + +__all__ = ["EnvironmentCreateResponse"] + + +class EnvironmentCreateResponse(BaseModel): + environment: Environment + """+resource get environment""" diff --git a/src/gitpod/types/environment_delete_params.py b/src/gitpod/types/environment_delete_params.py new file mode 100644 index 0000000..20ce84f --- /dev/null +++ b/src/gitpod/types/environment_delete_params.py @@ -0,0 +1,25 @@ +# 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__ = ["EnvironmentDeleteParams"] + + +class EnvironmentDeleteParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """environment_id specifies the environment that is going to delete. + + +required + """ + + force: bool + """ + force indicates whether the environment should be deleted forcefully When force + deleting an Environment, the Environment is removed immediately and environment + lifecycle is not respected. Force deleting can result in data loss on the + environment. + """ diff --git a/src/gitpod/types/environment_initializer.py b/src/gitpod/types/environment_initializer.py new file mode 100644 index 0000000..2a2866a --- /dev/null +++ b/src/gitpod/types/environment_initializer.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EnvironmentInitializer", "Spec", "SpecContextURL", "SpecGit"] + + +class SpecContextURL(BaseModel): + url: Optional[str] = None + """url is the URL from which the environment is created""" + + +class SpecGit(BaseModel): + checkout_location: Optional[str] = FieldInfo(alias="checkoutLocation", default=None) + """ + a path relative to the environment root in which the code will be checked out to + """ + + clone_target: Optional[str] = FieldInfo(alias="cloneTarget", default=None) + """the value for the clone target mode - use depends on the target mode""" + + remote_uri: Optional[str] = FieldInfo(alias="remoteUri", default=None) + """remote_uri is the Git remote origin""" + + target_mode: Optional[ + Literal[ + "CLONE_TARGET_MODE_UNSPECIFIED", + "CLONE_TARGET_MODE_REMOTE_HEAD", + "CLONE_TARGET_MODE_REMOTE_COMMIT", + "CLONE_TARGET_MODE_REMOTE_BRANCH", + "CLONE_TARGET_MODE_LOCAL_BRANCH", + ] + ] = FieldInfo(alias="targetMode", default=None) + """the target mode determines what gets checked out""" + + upstream_remote_uri: Optional[str] = FieldInfo(alias="upstreamRemoteUri", default=None) + """upstream_Remote_uri is the fork upstream of a repository""" + + +class Spec(BaseModel): + context_url: Optional[SpecContextURL] = FieldInfo(alias="contextUrl", default=None) + + git: Optional[SpecGit] = None + + +class EnvironmentInitializer(BaseModel): + specs: Optional[List[Spec]] = None diff --git a/src/gitpod/types/environment_initializer_param.py b/src/gitpod/types/environment_initializer_param.py new file mode 100644 index 0000000..695d836 --- /dev/null +++ b/src/gitpod/types/environment_initializer_param.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EnvironmentInitializerParam", "Spec", "SpecContextURL", "SpecGit"] + + +class SpecContextURL(TypedDict, total=False): + url: str + """url is the URL from which the environment is created""" + + +class SpecGit(TypedDict, total=False): + checkout_location: Annotated[str, PropertyInfo(alias="checkoutLocation")] + """ + a path relative to the environment root in which the code will be checked out to + """ + + clone_target: Annotated[str, PropertyInfo(alias="cloneTarget")] + """the value for the clone target mode - use depends on the target mode""" + + remote_uri: Annotated[str, PropertyInfo(alias="remoteUri")] + """remote_uri is the Git remote origin""" + + target_mode: Annotated[ + Literal[ + "CLONE_TARGET_MODE_UNSPECIFIED", + "CLONE_TARGET_MODE_REMOTE_HEAD", + "CLONE_TARGET_MODE_REMOTE_COMMIT", + "CLONE_TARGET_MODE_REMOTE_BRANCH", + "CLONE_TARGET_MODE_LOCAL_BRANCH", + ], + PropertyInfo(alias="targetMode"), + ] + """the target mode determines what gets checked out""" + + upstream_remote_uri: Annotated[str, PropertyInfo(alias="upstreamRemoteUri")] + """upstream_Remote_uri is the fork upstream of a repository""" + + +class Spec(TypedDict, total=False): + context_url: Annotated[SpecContextURL, PropertyInfo(alias="contextUrl")] + + git: SpecGit + + +class EnvironmentInitializerParam(TypedDict, total=False): + specs: Iterable[Spec] diff --git a/src/gitpod/types/environment_list_params.py b/src/gitpod/types/environment_list_params.py new file mode 100644 index 0000000..eedde71 --- /dev/null +++ b/src/gitpod/types/environment_list_params.py @@ -0,0 +1,81 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, Annotated, TypedDict + +from .._utils import PropertyInfo +from .runner_kind import RunnerKind +from .environment_phase import EnvironmentPhase + +__all__ = ["EnvironmentListParams", "Filter", "Pagination"] + + +class EnvironmentListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + """pagination contains the pagination options for listing environments""" + + +class Filter(TypedDict, total=False): + archival_status: Annotated[ + Optional[ + Literal[ + "ARCHIVAL_STATUS_UNSPECIFIED", + "ARCHIVAL_STATUS_ACTIVE", + "ARCHIVAL_STATUS_ARCHIVED", + "ARCHIVAL_STATUS_ALL", + ] + ], + PropertyInfo(alias="archivalStatus"), + ] + """archival_status filters the response based on environment archive status""" + + creator_ids: Annotated[List[str], PropertyInfo(alias="creatorIds")] + """ + creator_ids filters the response to only Environments created by specified + members + """ + + project_ids: Annotated[List[str], PropertyInfo(alias="projectIds")] + """ + project_ids filters the response to only Environments associated with the + specified projects + """ + + runner_ids: Annotated[List[str], PropertyInfo(alias="runnerIds")] + """ + runner_ids filters the response to only Environments running on these Runner IDs + """ + + runner_kinds: Annotated[List[RunnerKind], PropertyInfo(alias="runnerKinds")] + """ + runner_kinds filters the response to only Environments running on these Runner + Kinds + """ + + status_phases: Annotated[List[EnvironmentPhase], PropertyInfo(alias="statusPhases")] + """ + actual_phases is a list of phases the environment must be in for it to be + returned in the API call + """ + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/environment_mark_active_params.py b/src/gitpod/types/environment_mark_active_params.py new file mode 100644 index 0000000..0e10971 --- /dev/null +++ b/src/gitpod/types/environment_mark_active_params.py @@ -0,0 +1,18 @@ +# 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 +from .environment_activity_signal_param import EnvironmentActivitySignalParam + +__all__ = ["EnvironmentMarkActiveParams"] + + +class EnvironmentMarkActiveParams(TypedDict, total=False): + activity_signal: Annotated[EnvironmentActivitySignalParam, PropertyInfo(alias="activitySignal")] + """activity_signal specifies the activity.""" + + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """The ID of the environment to update activity for.""" diff --git a/src/gitpod/types/environment_metadata.py b/src/gitpod/types/environment_metadata.py new file mode 100644 index 0000000..67090e0 --- /dev/null +++ b/src/gitpod/types/environment_metadata.py @@ -0,0 +1,58 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.subject import Subject + +__all__ = ["EnvironmentMetadata"] + + +class EnvironmentMetadata(BaseModel): + annotations: Optional[Dict[str, str]] = None + """ + annotations are key/value pairs that gets attached to the environment. + +internal - not yet implemented + """ + + archived_at: Optional[datetime] = FieldInfo(alias="archivedAt", default=None) + """Time when the Environment was archived. + + If not set, the environment is not archived. + """ + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """Time when the Environment was created.""" + + creator: Optional[Subject] = None + """creator is the identity of the creator of the environment""" + + last_started_at: Optional[datetime] = FieldInfo(alias="lastStartedAt", default=None) + """Time when the Environment was last started (i.e. + + CreateEnvironment or StartEnvironment were called). + """ + + name: Optional[str] = None + """name is the name of the environment as specified by the user""" + + organization_id: Optional[str] = FieldInfo(alias="organizationId", default=None) + """organization_id is the ID of the organization that contains the environment""" + + original_context_url: Optional[str] = FieldInfo(alias="originalContextUrl", default=None) + """ + original_context_url is the normalized URL from which the environment was + created + """ + + project_id: Optional[str] = FieldInfo(alias="projectId", default=None) + """ + If the Environment was started from a project, the project_id will reference the + project. + """ + + runner_id: Optional[str] = FieldInfo(alias="runnerId", default=None) + """Runner is the ID of the runner that runs this environment.""" diff --git a/src/gitpod/types/environment_phase.py b/src/gitpod/types/environment_phase.py new file mode 100644 index 0000000..817644d --- /dev/null +++ b/src/gitpod/types/environment_phase.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["EnvironmentPhase"] + +EnvironmentPhase: TypeAlias = Literal[ + "ENVIRONMENT_PHASE_UNSPECIFIED", + "ENVIRONMENT_PHASE_CREATING", + "ENVIRONMENT_PHASE_STARTING", + "ENVIRONMENT_PHASE_RUNNING", + "ENVIRONMENT_PHASE_UPDATING", + "ENVIRONMENT_PHASE_STOPPING", + "ENVIRONMENT_PHASE_STOPPED", + "ENVIRONMENT_PHASE_DELETING", + "ENVIRONMENT_PHASE_DELETED", +] diff --git a/src/gitpod/types/environment_retrieve_params.py b/src/gitpod/types/environment_retrieve_params.py new file mode 100644 index 0000000..f470b6c --- /dev/null +++ b/src/gitpod/types/environment_retrieve_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EnvironmentRetrieveParams"] + + +class EnvironmentRetrieveParams(TypedDict, total=False): + environment_id: Required[Annotated[str, PropertyInfo(alias="environmentId")]] + """environment_id specifies the environment to get""" diff --git a/src/gitpod/types/environment_retrieve_response.py b/src/gitpod/types/environment_retrieve_response.py new file mode 100644 index 0000000..1409d07 --- /dev/null +++ b/src/gitpod/types/environment_retrieve_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .environment import Environment + +__all__ = ["EnvironmentRetrieveResponse"] + + +class EnvironmentRetrieveResponse(BaseModel): + environment: Environment + """+resource get environment""" diff --git a/src/gitpod/types/environment_spec.py b/src/gitpod/types/environment_spec.py new file mode 100644 index 0000000..a6ccaa6 --- /dev/null +++ b/src/gitpod/types/environment_spec.py @@ -0,0 +1,186 @@ +# 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 +from .admission_level import AdmissionLevel +from .environment_phase import EnvironmentPhase +from .environment_initializer import EnvironmentInitializer + +__all__ = [ + "EnvironmentSpec", + "AutomationsFile", + "Content", + "Devcontainer", + "DevcontainerDotfiles", + "Machine", + "Port", + "Secret", + "SSHPublicKey", + "Timeout", +] + + +class AutomationsFile(BaseModel): + automations_file_path: Optional[str] = FieldInfo(alias="automationsFilePath", default=None) + """ + automations_file_path is the path to the automations file that is applied in the + environment, relative to the repo root. path must not be absolute (start with a + /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + session: Optional[str] = None + + +class Content(BaseModel): + git_email: Optional[str] = FieldInfo(alias="gitEmail", default=None) + """The Git email address""" + + git_username: Optional[str] = FieldInfo(alias="gitUsername", default=None) + """The Git username""" + + initializer: Optional[EnvironmentInitializer] = None + """initializer configures how the environment is to be initialized""" + + session: Optional[str] = None + + +class DevcontainerDotfiles(BaseModel): + repository: str + """URL of a dotfiles Git repository (e.g. https://github.com/owner/repository)""" + + +class Devcontainer(BaseModel): + default_devcontainer_image: Optional[str] = FieldInfo(alias="defaultDevcontainerImage", default=None) + """ + default_devcontainer_image is the default image that is used to start the + devcontainer if no devcontainer config file is found + """ + + devcontainer_file_path: Optional[str] = FieldInfo(alias="devcontainerFilePath", default=None) + """ + devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + dotfiles: Optional[DevcontainerDotfiles] = None + """Experimental: dotfiles is the dotfiles configuration of the devcontainer""" + + session: Optional[str] = None + + +class Machine(BaseModel): + class_: Optional[str] = FieldInfo(alias="class", default=None) + """Class denotes the class of the environment we ought to start""" + + session: Optional[str] = None + + +class Port(BaseModel): + admission: Optional[AdmissionLevel] = None + """policy of this port""" + + name: Optional[str] = None + """name of this port""" + + port: Optional[int] = None + """port number""" + + +class Secret(BaseModel): + id: Optional[str] = None + """id is the unique identifier of the secret.""" + + container_registry_basic_auth_host: Optional[str] = FieldInfo(alias="containerRegistryBasicAuthHost", default=None) + """ + container_registry_basic_auth_host is the hostname of the container registry + that supports basic auth + """ + + environment_variable: Optional[str] = FieldInfo(alias="environmentVariable", default=None) + + file_path: Optional[str] = FieldInfo(alias="filePath", default=None) + """file_path is the path inside the devcontainer where the secret is mounted""" + + git_credential_host: Optional[str] = FieldInfo(alias="gitCredentialHost", default=None) + + name: Optional[str] = None + """name is the human readable description of the secret""" + + session: Optional[str] = None + """ + session indicated the current session of the secret. When the session does not + change, secrets are not reloaded in the environment. + """ + + source: Optional[str] = None + """source is the source of the secret, for now control-plane or runner""" + + source_ref: Optional[str] = FieldInfo(alias="sourceRef", default=None) + """source_ref into the source, in case of control-plane this is uuid of the secret""" + + +class SSHPublicKey(BaseModel): + id: Optional[str] = None + """id is the unique identifier of the public key""" + + value: Optional[str] = None + """value is the actual public key in the public key file format""" + + +class Timeout(BaseModel): + disconnected: Optional[str] = None + """ + inacitivity is the maximum time of disconnection before the environment is + stopped or paused. Minimum duration is 30 minutes. Set to 0 to disable. + """ + + +class EnvironmentSpec(BaseModel): + admission: Optional[AdmissionLevel] = None + """admission controlls who can access the environment and its ports.""" + + automations_file: Optional[AutomationsFile] = FieldInfo(alias="automationsFile", default=None) + """automations_file is the automations file spec of the environment""" + + content: Optional[Content] = None + """content is the content spec of the environment""" + + desired_phase: Optional[EnvironmentPhase] = FieldInfo(alias="desiredPhase", default=None) + """Phase is the desired phase of the environment""" + + devcontainer: Optional[Devcontainer] = None + """devcontainer is the devcontainer spec of the environment""" + + machine: Optional[Machine] = None + """machine is the machine spec of the environment""" + + ports: Optional[List[Port]] = None + """ports is the set of ports which ought to be exposed to the internet""" + + secrets: Optional[List[Secret]] = None + """secrets are confidential data that is mounted into the environment""" + + spec_version: Optional[str] = FieldInfo(alias="specVersion", default=None) + """version of the spec. + + The value of this field has no semantic meaning (e.g. don't interpret it as as a + timestamp), but it can be used to impose a partial order. If a.spec_version < + b.spec_version then a was the spec before b. + """ + + ssh_public_keys: Optional[List[SSHPublicKey]] = FieldInfo(alias="sshPublicKeys", default=None) + """ssh_public_keys are the public keys used to ssh into the environment""" + + timeout: Optional[Timeout] = None + """Timeout configures the environment timeout""" diff --git a/src/gitpod/types/environment_spec_param.py b/src/gitpod/types/environment_spec_param.py new file mode 100644 index 0000000..6e846a5 --- /dev/null +++ b/src/gitpod/types/environment_spec_param.py @@ -0,0 +1,193 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo +from .admission_level import AdmissionLevel +from .environment_phase import EnvironmentPhase +from .environment_initializer_param import EnvironmentInitializerParam + +__all__ = [ + "EnvironmentSpecParam", + "AutomationsFile", + "Content", + "Devcontainer", + "DevcontainerDotfiles", + "Machine", + "Port", + "Secret", + "SSHPublicKey", + "Timeout", +] + + +class AutomationsFile(TypedDict, total=False): + automations_file_path: Annotated[str, PropertyInfo(alias="automationsFilePath")] + """ + automations_file_path is the path to the automations file that is applied in the + environment, relative to the repo root. path must not be absolute (start with a + /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + session: str + + +class Content(TypedDict, total=False): + git_email: Annotated[str, PropertyInfo(alias="gitEmail")] + """The Git email address""" + + git_username: Annotated[str, PropertyInfo(alias="gitUsername")] + """The Git username""" + + initializer: EnvironmentInitializerParam + """initializer configures how the environment is to be initialized""" + + session: str + + +class DevcontainerDotfiles(TypedDict, total=False): + repository: Required[str] + """URL of a dotfiles Git repository (e.g. https://github.com/owner/repository)""" + + +class Devcontainer(TypedDict, total=False): + default_devcontainer_image: Annotated[str, PropertyInfo(alias="defaultDevcontainerImage")] + """ + default_devcontainer_image is the default image that is used to start the + devcontainer if no devcontainer config file is found + """ + + devcontainer_file_path: Annotated[str, PropertyInfo(alias="devcontainerFilePath")] + """ + devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + dotfiles: DevcontainerDotfiles + """Experimental: dotfiles is the dotfiles configuration of the devcontainer""" + + session: str + + +_MachineReservedKeywords = TypedDict( + "_MachineReservedKeywords", + { + "class": str, + }, + total=False, +) + + +class Machine(_MachineReservedKeywords, total=False): + session: str + + +class Port(TypedDict, total=False): + admission: AdmissionLevel + """policy of this port""" + + name: str + """name of this port""" + + port: int + """port number""" + + +class Secret(TypedDict, total=False): + id: str + """id is the unique identifier of the secret.""" + + container_registry_basic_auth_host: Annotated[str, PropertyInfo(alias="containerRegistryBasicAuthHost")] + """ + container_registry_basic_auth_host is the hostname of the container registry + that supports basic auth + """ + + environment_variable: Annotated[str, PropertyInfo(alias="environmentVariable")] + + file_path: Annotated[str, PropertyInfo(alias="filePath")] + """file_path is the path inside the devcontainer where the secret is mounted""" + + git_credential_host: Annotated[str, PropertyInfo(alias="gitCredentialHost")] + + name: str + """name is the human readable description of the secret""" + + session: str + """ + session indicated the current session of the secret. When the session does not + change, secrets are not reloaded in the environment. + """ + + source: str + """source is the source of the secret, for now control-plane or runner""" + + source_ref: Annotated[str, PropertyInfo(alias="sourceRef")] + """source_ref into the source, in case of control-plane this is uuid of the secret""" + + +class SSHPublicKey(TypedDict, total=False): + id: str + """id is the unique identifier of the public key""" + + value: str + """value is the actual public key in the public key file format""" + + +class Timeout(TypedDict, total=False): + disconnected: str + """ + inacitivity is the maximum time of disconnection before the environment is + stopped or paused. Minimum duration is 30 minutes. Set to 0 to disable. + """ + + +class EnvironmentSpecParam(TypedDict, total=False): + admission: AdmissionLevel + """admission controlls who can access the environment and its ports.""" + + automations_file: Annotated[AutomationsFile, PropertyInfo(alias="automationsFile")] + """automations_file is the automations file spec of the environment""" + + content: Content + """content is the content spec of the environment""" + + desired_phase: Annotated[EnvironmentPhase, PropertyInfo(alias="desiredPhase")] + """Phase is the desired phase of the environment""" + + devcontainer: Devcontainer + """devcontainer is the devcontainer spec of the environment""" + + machine: Machine + """machine is the machine spec of the environment""" + + ports: Iterable[Port] + """ports is the set of ports which ought to be exposed to the internet""" + + secrets: Iterable[Secret] + """secrets are confidential data that is mounted into the environment""" + + spec_version: Annotated[str, PropertyInfo(alias="specVersion")] + """version of the spec. + + The value of this field has no semantic meaning (e.g. don't interpret it as as a + timestamp), but it can be used to impose a partial order. If a.spec_version < + b.spec_version then a was the spec before b. + """ + + ssh_public_keys: Annotated[Iterable[SSHPublicKey], PropertyInfo(alias="sshPublicKeys")] + """ssh_public_keys are the public keys used to ssh into the environment""" + + timeout: Timeout + """Timeout configures the environment timeout""" diff --git a/src/gitpod/types/environment_start_params.py b/src/gitpod/types/environment_start_params.py new file mode 100644 index 0000000..83fe0a4 --- /dev/null +++ b/src/gitpod/types/environment_start_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EnvironmentStartParams"] + + +class EnvironmentStartParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """environment_id specifies which environment should be started.""" diff --git a/src/gitpod/types/environment_status.py b/src/gitpod/types/environment_status.py new file mode 100644 index 0000000..4595543 --- /dev/null +++ b/src/gitpod/types/environment_status.py @@ -0,0 +1,412 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .environment_phase import EnvironmentPhase +from .environment_activity_signal import EnvironmentActivitySignal + +__all__ = [ + "EnvironmentStatus", + "AutomationsFile", + "Content", + "ContentGit", + "ContentGitChangedFile", + "Devcontainer", + "EnvironmentURLs", + "EnvironmentURLsPort", + "EnvironmentURLsSSH", + "Machine", + "MachineVersions", + "RunnerAck", + "Secret", + "SSHPublicKey", +] + + +class AutomationsFile(BaseModel): + automations_file_path: Optional[str] = FieldInfo(alias="automationsFilePath", default=None) + """ + automations_file_path is the path to the automations file relative to the repo + root. + """ + + automations_file_presence: Optional[ + Literal["PRESENCE_UNSPECIFIED", "PRESENCE_ABSENT", "PRESENCE_DISCOVERED", "PRESENCE_SPECIFIED"] + ] = FieldInfo(alias="automationsFilePresence", default=None) + """ + automations_file_presence indicates how an automations file is present in the + environment. + """ + + failure_message: Optional[str] = FieldInfo(alias="failureMessage", default=None) + """ + failure_message contains the reason the automations file failed to be applied. + This is only set if the phase is FAILED. + """ + + phase: Optional[ + Literal[ + "CONTENT_PHASE_UNSPECIFIED", + "CONTENT_PHASE_CREATING", + "CONTENT_PHASE_INITIALIZING", + "CONTENT_PHASE_READY", + "CONTENT_PHASE_UPDATING", + "CONTENT_PHASE_FAILED", + ] + ] = None + """phase is the current phase of the automations file.""" + + session: Optional[str] = None + """ + session is the automations file session that is currently applied in the + environment. + """ + + warning_message: Optional[str] = FieldInfo(alias="warningMessage", default=None) + """warning_message contains warnings, e.g. + + when no triggers are defined in the automations file. + """ + + +class ContentGitChangedFile(BaseModel): + change_type: Optional[ + Literal[ + "CHANGE_TYPE_UNSPECIFIED", + "CHANGE_TYPE_ADDED", + "CHANGE_TYPE_MODIFIED", + "CHANGE_TYPE_DELETED", + "CHANGE_TYPE_RENAMED", + "CHANGE_TYPE_COPIED", + "CHANGE_TYPE_UPDATED_BUT_UNMERGED", + "CHANGE_TYPE_UNTRACKED", + ] + ] = FieldInfo(alias="changeType", default=None) + """ChangeType is the type of change that happened to the file""" + + path: Optional[str] = None + """path is the path of the file""" + + +class ContentGit(BaseModel): + branch: Optional[str] = None + """branch is branch we're currently on""" + + changed_files: Optional[List[ContentGitChangedFile]] = FieldInfo(alias="changedFiles", default=None) + """ + changed_files is an array of changed files in the environment, possibly + truncated + """ + + clone_url: Optional[str] = FieldInfo(alias="cloneUrl", default=None) + """ + clone_url is the repository url as you would pass it to "git clone". Only HTTPS + clone URLs are supported. + """ + + latest_commit: Optional[str] = FieldInfo(alias="latestCommit", default=None) + """latest_commit is the most recent commit on the current branch""" + + total_changed_files: Optional[int] = FieldInfo(alias="totalChangedFiles", default=None) + + total_unpushed_commits: Optional[int] = FieldInfo(alias="totalUnpushedCommits", default=None) + """the total number of unpushed changes""" + + unpushed_commits: Optional[List[str]] = FieldInfo(alias="unpushedCommits", default=None) + """ + unpushed_commits is an array of unpushed changes in the environment, possibly + truncated + """ + + +class Content(BaseModel): + content_location_in_machine: Optional[str] = FieldInfo(alias="contentLocationInMachine", default=None) + """content_location_in_machine is the location of the content in the machine""" + + failure_message: Optional[str] = FieldInfo(alias="failureMessage", default=None) + """failure_message contains the reason the content initialization failed.""" + + git: Optional[ContentGit] = None + """ + git is the Git working copy status of the environment. Note: this is a + best-effort field and more often than not will not be present. Its absence does + not indicate the absence of a working copy. + """ + + phase: Optional[ + Literal[ + "CONTENT_PHASE_UNSPECIFIED", + "CONTENT_PHASE_CREATING", + "CONTENT_PHASE_INITIALIZING", + "CONTENT_PHASE_READY", + "CONTENT_PHASE_UPDATING", + "CONTENT_PHASE_FAILED", + ] + ] = None + """phase is the current phase of the environment content""" + + session: Optional[str] = None + """session is the session that is currently active in the environment.""" + + warning_message: Optional[str] = FieldInfo(alias="warningMessage", default=None) + """warning_message contains warnings, e.g. + + when the content is present but not in the expected state. + """ + + +class Devcontainer(BaseModel): + container_id: Optional[str] = FieldInfo(alias="containerId", default=None) + """container_id is the ID of the container.""" + + container_name: Optional[str] = FieldInfo(alias="containerName", default=None) + """ + container_name is the name of the container that is used to connect to the + devcontainer + """ + + devcontainerconfig_in_sync: Optional[bool] = FieldInfo(alias="devcontainerconfigInSync", default=None) + """devcontainerconfig_in_sync indicates if the devcontainer is up to date w.r.t. + + the devcontainer config file. + """ + + devcontainer_file_path: Optional[str] = FieldInfo(alias="devcontainerFilePath", default=None) + """ + devcontainer_file_path is the path to the devcontainer file relative to the repo + root + """ + + devcontainer_file_presence: Optional[ + Literal["PRESENCE_UNSPECIFIED", "PRESENCE_GENERATED", "PRESENCE_DISCOVERED", "PRESENCE_SPECIFIED"] + ] = FieldInfo(alias="devcontainerFilePresence", default=None) + """ + devcontainer_file_presence indicates how the devcontainer file is present in the + repo. + """ + + failure_message: Optional[str] = FieldInfo(alias="failureMessage", default=None) + """failure_message contains the reason the devcontainer failed to operate.""" + + phase: Optional[ + Literal["PHASE_UNSPECIFIED", "PHASE_CREATING", "PHASE_RUNNING", "PHASE_STOPPED", "PHASE_FAILED"] + ] = None + """phase is the current phase of the devcontainer""" + + remote_user: Optional[str] = FieldInfo(alias="remoteUser", default=None) + """remote_user is the user that is used to connect to the devcontainer""" + + remote_workspace_folder: Optional[str] = FieldInfo(alias="remoteWorkspaceFolder", default=None) + """ + remote_workspace_folder is the folder that is used to connect to the + devcontainer + """ + + secrets_in_sync: Optional[bool] = FieldInfo(alias="secretsInSync", default=None) + """secrets_in_sync indicates if the secrets are up to date w.r.t. + + the running devcontainer. + """ + + session: Optional[str] = None + """session is the session that is currently active in the devcontainer.""" + + warning_message: Optional[str] = FieldInfo(alias="warningMessage", default=None) + """warning_message contains warnings, e.g. + + when the devcontainer is present but not in the expected state. + """ + + +class EnvironmentURLsPort(BaseModel): + port: Optional[int] = None + """port is the port number of the environment port""" + + url: Optional[str] = None + """url is the URL at which the environment port can be accessed""" + + +class EnvironmentURLsSSH(BaseModel): + url: Optional[str] = None + + +class EnvironmentURLs(BaseModel): + logs: Optional[str] = None + """logs is the URL at which the environment logs can be accessed.""" + + ports: Optional[List[EnvironmentURLsPort]] = None + + ssh: Optional[EnvironmentURLsSSH] = None + """SSH is the URL at which the environment can be accessed via SSH.""" + + +class MachineVersions(BaseModel): + supervisor_commit: Optional[str] = FieldInfo(alias="supervisorCommit", default=None) + + supervisor_version: Optional[str] = FieldInfo(alias="supervisorVersion", default=None) + + +class Machine(BaseModel): + failure_message: Optional[str] = FieldInfo(alias="failureMessage", default=None) + """failure_message contains the reason the machine failed to operate.""" + + phase: Optional[ + Literal[ + "PHASE_UNSPECIFIED", + "PHASE_CREATING", + "PHASE_STARTING", + "PHASE_RUNNING", + "PHASE_STOPPING", + "PHASE_STOPPED", + "PHASE_DELETING", + "PHASE_DELETED", + ] + ] = None + """phase is the current phase of the environment machine""" + + session: Optional[str] = None + """session is the session that is currently active in the machine.""" + + timeout: Optional[str] = None + """timeout contains the reason the environment has timed out. + + If this field is empty, the environment has not timed out. + """ + + versions: Optional[MachineVersions] = None + """versions contains the versions of components in the machine.""" + + warning_message: Optional[str] = FieldInfo(alias="warningMessage", default=None) + """warning_message contains warnings, e.g. + + when the machine is present but not in the expected state. + """ + + +class RunnerAck(BaseModel): + message: Optional[str] = None + + spec_version: Optional[str] = FieldInfo(alias="specVersion", default=None) + + status_code: Optional[ + Literal[ + "STATUS_CODE_UNSPECIFIED", + "STATUS_CODE_OK", + "STATUS_CODE_INVALID_RESOURCE", + "STATUS_CODE_FAILED_PRECONDITION", + ] + ] = FieldInfo(alias="statusCode", default=None) + + +class Secret(BaseModel): + id: Optional[str] = None + """id is the unique identifier of the secret.""" + + failure_message: Optional[str] = FieldInfo(alias="failureMessage", default=None) + """failure_message contains the reason the secret failed to be materialize.""" + + phase: Optional[ + Literal[ + "CONTENT_PHASE_UNSPECIFIED", + "CONTENT_PHASE_CREATING", + "CONTENT_PHASE_INITIALIZING", + "CONTENT_PHASE_READY", + "CONTENT_PHASE_UPDATING", + "CONTENT_PHASE_FAILED", + ] + ] = None + + secret_name: Optional[str] = FieldInfo(alias="secretName", default=None) + + session: Optional[str] = None + """session is the session that is currently active in the environment.""" + + warning_message: Optional[str] = FieldInfo(alias="warningMessage", default=None) + """warning_message contains warnings, e.g. + + when the secret is present but not in the expected state. + """ + + +class SSHPublicKey(BaseModel): + id: Optional[str] = None + """id is the unique identifier of the public key""" + + phase: Optional[ + Literal[ + "CONTENT_PHASE_UNSPECIFIED", + "CONTENT_PHASE_CREATING", + "CONTENT_PHASE_INITIALIZING", + "CONTENT_PHASE_READY", + "CONTENT_PHASE_UPDATING", + "CONTENT_PHASE_FAILED", + ] + ] = None + """phase is the current phase of the public key""" + + +class EnvironmentStatus(BaseModel): + activity_signal: Optional[EnvironmentActivitySignal] = FieldInfo(alias="activitySignal", default=None) + """activity_signal is the last activity signal for the environment.""" + + automations_file: Optional[AutomationsFile] = FieldInfo(alias="automationsFile", default=None) + """automations_file contains the status of the automations file.""" + + content: Optional[Content] = None + """content contains the status of the environment content.""" + + devcontainer: Optional[Devcontainer] = None + """devcontainer contains the status of the devcontainer.""" + + environment_urls: Optional[EnvironmentURLs] = FieldInfo(alias="environmentUrls", default=None) + """ + environment_url contains the URL at which the environment can be accessed. This + field is only set if the environment is running. + """ + + failure_message: Optional[List[str]] = FieldInfo(alias="failureMessage", default=None) + """failure_message summarises why the environment failed to operate. + + If this is non-empty the environment has failed to operate and will likely + transition to a stopped state. + """ + + machine: Optional[Machine] = None + """machine contains the status of the environment machine""" + + phase: Optional[EnvironmentPhase] = None + """ + the phase of an environment is a simple, high-level summary of where the + environment is in its lifecycle + """ + + runner_ack: Optional[RunnerAck] = FieldInfo(alias="runnerAck", default=None) + """ + runner_ack contains the acknowledgement from the runner that is has received the + environment spec. + """ + + secrets: Optional[List[Secret]] = None + """secrets contains the status of the environment secrets""" + + ssh_public_keys: Optional[List[SSHPublicKey]] = FieldInfo(alias="sshPublicKeys", default=None) + """ssh_public_keys contains the status of the environment ssh public keys""" + + status_version: Optional[str] = FieldInfo(alias="statusVersion", default=None) + """version of the status update. + + Environment instances themselves are unversioned, but their status has different + versions. The value of this field has no semantic meaning (e.g. don't interpret + it as as a timestamp), but it can be used to impose a partial order. If + a.status_version < b.status_version then a was the status before b. + """ + + warning_message: Optional[List[str]] = FieldInfo(alias="warningMessage", default=None) + """warning_message contains warnings, e.g. + + when the environment is present but not in the expected state. + """ diff --git a/src/gitpod/types/environment_stop_params.py b/src/gitpod/types/environment_stop_params.py new file mode 100644 index 0000000..885db41 --- /dev/null +++ b/src/gitpod/types/environment_stop_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 Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EnvironmentStopParams"] + + +class EnvironmentStopParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """environment_id specifies which environment should be stopped. + + +required + """ diff --git a/src/gitpod/types/environment_unarchive_params.py b/src/gitpod/types/environment_unarchive_params.py new file mode 100644 index 0000000..862c3be --- /dev/null +++ b/src/gitpod/types/environment_unarchive_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 Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EnvironmentUnarchiveParams"] + + +class EnvironmentUnarchiveParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """environment_id specifies the environment to unarchive. + + +required + """ diff --git a/src/gitpod/types/environment_update_params.py b/src/gitpod/types/environment_update_params.py new file mode 100644 index 0000000..60d7bfc --- /dev/null +++ b/src/gitpod/types/environment_update_params.py @@ -0,0 +1,134 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo +from .admission_level import AdmissionLevel +from .environment_initializer_param import EnvironmentInitializerParam + +__all__ = [ + "EnvironmentUpdateParams", + "Metadata", + "Spec", + "SpecAutomationsFile", + "SpecContent", + "SpecDevcontainer", + "SpecPort", + "SpecSSHPublicKey", + "SpecTimeout", +] + + +class EnvironmentUpdateParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """environment_id specifies which environment should be updated. + + +required + """ + + metadata: Optional[Metadata] + + spec: Optional[Spec] + + +class Metadata(TypedDict, total=False): + name: Optional[str] + """name is the user-defined display name of the environment""" + + +class SpecAutomationsFile(TypedDict, total=False): + automations_file_path: Annotated[Optional[str], PropertyInfo(alias="automationsFilePath")] + """ + automations_file_path is the path to the automations file that is applied in the + environment, relative to the repo root. path must not be absolute (start with a + /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + session: Optional[str] + + +class SpecContent(TypedDict, total=False): + git_email: Annotated[Optional[str], PropertyInfo(alias="gitEmail")] + """The Git email address""" + + git_username: Annotated[Optional[str], PropertyInfo(alias="gitUsername")] + """The Git username""" + + initializer: Optional[EnvironmentInitializerParam] + """initializer configures how the environment is to be initialized""" + + session: Optional[str] + """session should be changed to trigger a content reinitialization""" + + +class SpecDevcontainer(TypedDict, total=False): + devcontainer_file_path: Annotated[Optional[str], PropertyInfo(alias="devcontainerFilePath")] + """ + devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + session: Optional[str] + """session should be changed to trigger a devcontainer rebuild""" + + +class SpecPort(TypedDict, total=False): + admission: AdmissionLevel + """policy of this port""" + + name: str + """name of this port""" + + port: int + """port number""" + + +class SpecSSHPublicKey(TypedDict, total=False): + id: str + """id is the unique identifier of the public key""" + + value: Optional[str] + """ + value is the actual public key in the public key file format if not provided, + the public key will be removed + """ + + +class SpecTimeout(TypedDict, total=False): + disconnected: Optional[str] + """ + inacitivity is the maximum time of disconnection before the environment is + stopped or paused. Minimum duration is 30 minutes. Set to 0 to disable. + """ + + +class Spec(TypedDict, total=False): + automations_file: Annotated[Optional[SpecAutomationsFile], PropertyInfo(alias="automationsFile")] + """automations_file is the automations file spec of the environment""" + + content: Optional[SpecContent] + + devcontainer: Optional[SpecDevcontainer] + + ports: Iterable[SpecPort] + """ports controls port sharing""" + + ssh_public_keys: Annotated[Iterable[SpecSSHPublicKey], PropertyInfo(alias="sshPublicKeys")] + """ + ssh_public_keys are the public keys to update empty array means nothing to + update + """ + + timeout: Optional[SpecTimeout] + """Timeout configures the environment timeout""" diff --git a/src/gitpod/types/environment_usage_record.py b/src/gitpod/types/environment_usage_record.py new file mode 100644 index 0000000..59c85a7 --- /dev/null +++ b/src/gitpod/types/environment_usage_record.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EnvironmentUsageRecord"] + + +class EnvironmentUsageRecord(BaseModel): + id: Optional[str] = None + """Environment usage record ID.""" + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """Time when the environment was created.""" + + environment_class_id: Optional[str] = FieldInfo(alias="environmentClassId", default=None) + """Environment class ID associated with the record.""" + + environment_id: Optional[str] = FieldInfo(alias="environmentId", default=None) + """Environment ID associated with the record.""" + + project_id: Optional[str] = FieldInfo(alias="projectId", default=None) + """Project ID associated with the environment (if available).""" + + runner_id: Optional[str] = FieldInfo(alias="runnerId", default=None) + """Runner ID associated with the environment.""" + + stopped_at: Optional[datetime] = FieldInfo(alias="stoppedAt", default=None) + """Time when the environment was stopped.""" + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """ + User ID is the ID of the user who created the environment associated with the + record. + """ diff --git a/src/gitpod/types/environments/__init__.py b/src/gitpod/types/environments/__init__.py new file mode 100644 index 0000000..2a0fe22 --- /dev/null +++ b/src/gitpod/types/environments/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .class_list_params import ClassListParams as ClassListParams +from .automations_file_param import AutomationsFileParam as AutomationsFileParam +from .automation_upsert_params import AutomationUpsertParams as AutomationUpsertParams +from .automation_upsert_response import AutomationUpsertResponse as AutomationUpsertResponse diff --git a/src/gitpod/types/environments/automation_upsert_params.py b/src/gitpod/types/environments/automation_upsert_params.py new file mode 100644 index 0000000..754ae89 --- /dev/null +++ b/src/gitpod/types/environments/automation_upsert_params.py @@ -0,0 +1,22 @@ +# 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 +from .automations_file_param import AutomationsFileParam + +__all__ = ["AutomationUpsertParams"] + + +class AutomationUpsertParams(TypedDict, total=False): + automations_file: Annotated[AutomationsFileParam, PropertyInfo(alias="automationsFile")] + """ + WARN: Do not remove any field here, as it will break reading automation yaml + files. We error if there are any unknown fields in the yaml (to ensure the yaml + is correct), but would break if we removed any fields. This includes marking a + field as "reserved" in the proto file, this will also break reading the yaml. + """ + + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] diff --git a/src/gitpod/types/environments/automation_upsert_response.py b/src/gitpod/types/environments/automation_upsert_response.py new file mode 100644 index 0000000..f01ae1b --- /dev/null +++ b/src/gitpod/types/environments/automation_upsert_response.py @@ -0,0 +1,15 @@ +# 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__ = ["AutomationUpsertResponse"] + + +class AutomationUpsertResponse(BaseModel): + updated_service_ids: Optional[List[str]] = FieldInfo(alias="updatedServiceIds", default=None) + + updated_task_ids: Optional[List[str]] = FieldInfo(alias="updatedTaskIds", default=None) diff --git a/src/gitpod/types/environments/automations/__init__.py b/src/gitpod/types/environments/automations/__init__.py new file mode 100644 index 0000000..d6c647a --- /dev/null +++ b/src/gitpod/types/environments/automations/__init__.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .service import Service as Service +from .service_spec import ServiceSpec as ServiceSpec +from .service_phase import ServicePhase as ServicePhase +from .service_status import ServiceStatus as ServiceStatus +from .service_metadata import ServiceMetadata as ServiceMetadata +from .task_list_params import TaskListParams as TaskListParams +from .task_start_params import TaskStartParams as TaskStartParams +from .service_spec_param import ServiceSpecParam as ServiceSpecParam +from .task_create_params import TaskCreateParams as TaskCreateParams +from .task_delete_params import TaskDeleteParams as TaskDeleteParams +from .task_update_params import TaskUpdateParams as TaskUpdateParams +from .service_list_params import ServiceListParams as ServiceListParams +from .service_stop_params import ServiceStopParams as ServiceStopParams +from .task_start_response import TaskStartResponse as TaskStartResponse +from .service_start_params import ServiceStartParams as ServiceStartParams +from .task_create_response import TaskCreateResponse as TaskCreateResponse +from .task_retrieve_params import TaskRetrieveParams as TaskRetrieveParams +from .service_create_params import ServiceCreateParams as ServiceCreateParams +from .service_delete_params import ServiceDeleteParams as ServiceDeleteParams +from .service_update_params import ServiceUpdateParams as ServiceUpdateParams +from .service_metadata_param import ServiceMetadataParam as ServiceMetadataParam +from .task_retrieve_response import TaskRetrieveResponse as TaskRetrieveResponse +from .service_create_response import ServiceCreateResponse as ServiceCreateResponse +from .service_retrieve_params import ServiceRetrieveParams as ServiceRetrieveParams +from .service_retrieve_response import ServiceRetrieveResponse as ServiceRetrieveResponse diff --git a/src/gitpod/types/environments/automations/service.py b/src/gitpod/types/environments/automations/service.py new file mode 100644 index 0000000..9dbb5aa --- /dev/null +++ b/src/gitpod/types/environments/automations/service.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from .service_spec import ServiceSpec +from .service_status import ServiceStatus +from .service_metadata import ServiceMetadata + +__all__ = ["Service"] + + +class Service(BaseModel): + id: str + + environment_id: Optional[str] = FieldInfo(alias="environmentId", default=None) + + metadata: Optional[ServiceMetadata] = None + + spec: Optional[ServiceSpec] = None + + status: Optional[ServiceStatus] = None diff --git a/src/gitpod/types/environments/automations/service_create_params.py b/src/gitpod/types/environments/automations/service_create_params.py new file mode 100644 index 0000000..248cd55 --- /dev/null +++ b/src/gitpod/types/environments/automations/service_create_params.py @@ -0,0 +1,19 @@ +# 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 +from .service_spec_param import ServiceSpecParam +from .service_metadata_param import ServiceMetadataParam + +__all__ = ["ServiceCreateParams"] + + +class ServiceCreateParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + + metadata: ServiceMetadataParam + + spec: ServiceSpecParam diff --git a/src/gitpod/types/environments/automations/service_create_response.py b/src/gitpod/types/environments/automations/service_create_response.py new file mode 100644 index 0000000..0aa85db --- /dev/null +++ b/src/gitpod/types/environments/automations/service_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .service import Service +from ...._models import BaseModel + +__all__ = ["ServiceCreateResponse"] + + +class ServiceCreateResponse(BaseModel): + service: Service diff --git a/src/gitpod/types/environments/automations/service_delete_params.py b/src/gitpod/types/environments/automations/service_delete_params.py new file mode 100644 index 0000000..2fc5f3d --- /dev/null +++ b/src/gitpod/types/environments/automations/service_delete_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ServiceDeleteParams"] + + +class ServiceDeleteParams(TypedDict, total=False): + id: str + + force: bool diff --git a/src/gitpod/types/environments/automations/service_list_params.py b/src/gitpod/types/environments/automations/service_list_params.py new file mode 100644 index 0000000..c2c08b0 --- /dev/null +++ b/src/gitpod/types/environments/automations/service_list_params.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["ServiceListParams", "Filter", "Pagination"] + + +class ServiceListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + """filter contains the filter options for listing services""" + + pagination: Pagination + """pagination contains the pagination options for listing services""" + + +class Filter(TypedDict, total=False): + environment_ids: Annotated[List[str], PropertyInfo(alias="environmentIds")] + """environment_ids filters the response to only services of these environments""" + + references: List[str] + """references filters the response to only services with these references""" + + service_ids: Annotated[List[str], PropertyInfo(alias="serviceIds")] + """service_ids filters the response to only services with these IDs""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/environments/automations/service_metadata.py b/src/gitpod/types/environments/automations/service_metadata.py new file mode 100644 index 0000000..4555022 --- /dev/null +++ b/src/gitpod/types/environments/automations/service_metadata.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from ...shared.subject import Subject +from ...shared.automation_trigger import AutomationTrigger + +__all__ = ["ServiceMetadata"] + + +class ServiceMetadata(BaseModel): + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """created_at is the time the service was created.""" + + creator: Optional[Subject] = None + """creator describes the principal who created the service.""" + + description: Optional[str] = None + """description is a user-facing description for the service. + + It can be used to provide context and documentation for the service. + """ + + name: Optional[str] = None + """name is a user-facing name for the service. + + Unlike the reference, this field is not unique, and not referenced by the + system. This is a short descriptive name for the service. + """ + + reference: Optional[str] = None + """ + reference is a user-facing identifier for the service which must be unique on + the environment. It is used to express dependencies between services, and to + identify the service in user interactions (e.g. the CLI). + """ + + triggered_by: Optional[List[AutomationTrigger]] = FieldInfo(alias="triggeredBy", default=None) + """triggered_by is a list of trigger that start the service.""" diff --git a/src/gitpod/types/environments/automations/service_metadata_param.py b/src/gitpod/types/environments/automations/service_metadata_param.py new file mode 100644 index 0000000..669b250 --- /dev/null +++ b/src/gitpod/types/environments/automations/service_metadata_param.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo +from ...shared_params.subject import Subject +from ...shared_params.automation_trigger import AutomationTrigger + +__all__ = ["ServiceMetadataParam"] + + +class ServiceMetadataParam(TypedDict, total=False): + created_at: Annotated[Union[str, datetime], PropertyInfo(alias="createdAt", format="iso8601")] + """created_at is the time the service was created.""" + + creator: Subject + """creator describes the principal who created the service.""" + + description: str + """description is a user-facing description for the service. + + It can be used to provide context and documentation for the service. + """ + + name: str + """name is a user-facing name for the service. + + Unlike the reference, this field is not unique, and not referenced by the + system. This is a short descriptive name for the service. + """ + + reference: str + """ + reference is a user-facing identifier for the service which must be unique on + the environment. It is used to express dependencies between services, and to + identify the service in user interactions (e.g. the CLI). + """ + + triggered_by: Annotated[Iterable[AutomationTrigger], PropertyInfo(alias="triggeredBy")] + """triggered_by is a list of trigger that start the service.""" diff --git a/src/gitpod/types/environments/automations/service_phase.py b/src/gitpod/types/environments/automations/service_phase.py new file mode 100644 index 0000000..df4c820 --- /dev/null +++ b/src/gitpod/types/environments/automations/service_phase.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ServicePhase"] + +ServicePhase: TypeAlias = Literal[ + "SERVICE_PHASE_UNSPECIFIED", + "SERVICE_PHASE_STARTING", + "SERVICE_PHASE_RUNNING", + "SERVICE_PHASE_STOPPING", + "SERVICE_PHASE_STOPPED", + "SERVICE_PHASE_FAILED", + "SERVICE_PHASE_DELETED", +] diff --git a/src/gitpod/types/environments/automations/service_retrieve_params.py b/src/gitpod/types/environments/automations/service_retrieve_params.py new file mode 100644 index 0000000..857888a --- /dev/null +++ b/src/gitpod/types/environments/automations/service_retrieve_params.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 TypedDict + +__all__ = ["ServiceRetrieveParams"] + + +class ServiceRetrieveParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/environments/automations/service_retrieve_response.py b/src/gitpod/types/environments/automations/service_retrieve_response.py new file mode 100644 index 0000000..e377837 --- /dev/null +++ b/src/gitpod/types/environments/automations/service_retrieve_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .service import Service +from ...._models import BaseModel + +__all__ = ["ServiceRetrieveResponse"] + + +class ServiceRetrieveResponse(BaseModel): + service: Service diff --git a/src/gitpod/types/environments/automations/service_spec.py b/src/gitpod/types/environments/automations/service_spec.py new file mode 100644 index 0000000..7e160fe --- /dev/null +++ b/src/gitpod/types/environments/automations/service_spec.py @@ -0,0 +1,72 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from .service_phase import ServicePhase +from ...shared.runs_on import RunsOn + +__all__ = ["ServiceSpec", "Commands"] + + +class Commands(BaseModel): + ready: Optional[str] = None + """ + ready is an optional command that is run repeatedly until it exits with a zero + exit code. If set, the service will first go into a Starting phase, and then + into a Running phase once the ready command exits with a zero exit code. + """ + + start: Optional[str] = None + """ + start is the command to start and run the service. If start exits, the service + will transition to the following phase: + + - Stopped: if the exit code is 0 + - Failed: if the exit code is not 0 If the stop command is not set, the start + command will receive a SIGTERM signal when the service is requested to stop. + If it does not exit within 2 minutes, it will receive a SIGKILL signal. + """ + + stop: Optional[str] = None + """ + stop is an optional command that runs when the service is requested to stop. If + set, instead of sending a SIGTERM signal to the start command, the stop command + will be run. Once the stop command exits, the start command will receive a + SIGKILL signal. If the stop command exits with a non-zero exit code, the service + will transition to the Failed phase. If the stop command does not exit within 2 + minutes, a SIGKILL signal will be sent to both the start and stop commands. + """ + + +class ServiceSpec(BaseModel): + commands: Optional[Commands] = None + """ + commands contains the commands to start, stop and check the readiness of the + service + """ + + desired_phase: Optional[ServicePhase] = FieldInfo(alias="desiredPhase", default=None) + """desired_phase is the phase the service should be in. + + Used to start or stop the service. + """ + + runs_on: Optional[RunsOn] = FieldInfo(alias="runsOn", default=None) + """runs_on specifies the environment the service should run on.""" + + session: Optional[str] = None + """session should be changed to trigger a restart of the service. + + If a service exits it will not be restarted until the session is changed. + """ + + spec_version: Optional[str] = FieldInfo(alias="specVersion", default=None) + """version of the spec. + + The value of this field has no semantic meaning (e.g. don't interpret it as as a + timestamp), but it can be used to impose a partial order. If a.spec_version < + b.spec_version then a was the spec before b. + """ diff --git a/src/gitpod/types/environments/automations/service_spec_param.py b/src/gitpod/types/environments/automations/service_spec_param.py new file mode 100644 index 0000000..469be0e --- /dev/null +++ b/src/gitpod/types/environments/automations/service_spec_param.py @@ -0,0 +1,72 @@ +# 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 +from .service_phase import ServicePhase +from ...shared_params.runs_on import RunsOn + +__all__ = ["ServiceSpecParam", "Commands"] + + +class Commands(TypedDict, total=False): + ready: str + """ + ready is an optional command that is run repeatedly until it exits with a zero + exit code. If set, the service will first go into a Starting phase, and then + into a Running phase once the ready command exits with a zero exit code. + """ + + start: str + """ + start is the command to start and run the service. If start exits, the service + will transition to the following phase: + + - Stopped: if the exit code is 0 + - Failed: if the exit code is not 0 If the stop command is not set, the start + command will receive a SIGTERM signal when the service is requested to stop. + If it does not exit within 2 minutes, it will receive a SIGKILL signal. + """ + + stop: str + """ + stop is an optional command that runs when the service is requested to stop. If + set, instead of sending a SIGTERM signal to the start command, the stop command + will be run. Once the stop command exits, the start command will receive a + SIGKILL signal. If the stop command exits with a non-zero exit code, the service + will transition to the Failed phase. If the stop command does not exit within 2 + minutes, a SIGKILL signal will be sent to both the start and stop commands. + """ + + +class ServiceSpecParam(TypedDict, total=False): + commands: Commands + """ + commands contains the commands to start, stop and check the readiness of the + service + """ + + desired_phase: Annotated[ServicePhase, PropertyInfo(alias="desiredPhase")] + """desired_phase is the phase the service should be in. + + Used to start or stop the service. + """ + + runs_on: Annotated[RunsOn, PropertyInfo(alias="runsOn")] + """runs_on specifies the environment the service should run on.""" + + session: str + """session should be changed to trigger a restart of the service. + + If a service exits it will not be restarted until the session is changed. + """ + + spec_version: Annotated[str, PropertyInfo(alias="specVersion")] + """version of the spec. + + The value of this field has no semantic meaning (e.g. don't interpret it as as a + timestamp), but it can be used to impose a partial order. If a.spec_version < + b.spec_version then a was the spec before b. + """ diff --git a/src/gitpod/types/environments/automations/service_start_params.py b/src/gitpod/types/environments/automations/service_start_params.py new file mode 100644 index 0000000..237ab1e --- /dev/null +++ b/src/gitpod/types/environments/automations/service_start_params.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 TypedDict + +__all__ = ["ServiceStartParams"] + + +class ServiceStartParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/environments/automations/service_status.py b/src/gitpod/types/environments/automations/service_status.py new file mode 100644 index 0000000..b95049b --- /dev/null +++ b/src/gitpod/types/environments/automations/service_status.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from .service_phase import ServicePhase + +__all__ = ["ServiceStatus"] + + +class ServiceStatus(BaseModel): + failure_message: Optional[str] = FieldInfo(alias="failureMessage", default=None) + """failure_message summarises why the service failed to operate. + + If this is non-empty the service has failed to operate and will likely + transition to a failed state. + """ + + log_url: Optional[str] = FieldInfo(alias="logUrl", default=None) + """log_url contains the URL at which the service logs can be accessed.""" + + output: Optional[Dict[str, str]] = None + """ + output contains the output of the service. setting an output field to empty + string will unset it. + """ + + phase: Optional[ServicePhase] = None + """phase is the current phase of the service.""" + + session: Optional[str] = None + """session is the current session of the service.""" + + status_version: Optional[str] = FieldInfo(alias="statusVersion", default=None) + """version of the status update. + + Service instances themselves are unversioned, but their status has different + versions. The value of this field has no semantic meaning (e.g. don't interpret + it as as a timestamp), but it can be used to impose a partial order. If + a.status_version < b.status_version then a was the status before b. + """ diff --git a/src/gitpod/types/environments/automations/service_stop_params.py b/src/gitpod/types/environments/automations/service_stop_params.py new file mode 100644 index 0000000..fcb5e25 --- /dev/null +++ b/src/gitpod/types/environments/automations/service_stop_params.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 TypedDict + +__all__ = ["ServiceStopParams"] + + +class ServiceStopParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/environments/automations/service_update_params.py b/src/gitpod/types/environments/automations/service_update_params.py new file mode 100644 index 0000000..3fba2a0 --- /dev/null +++ b/src/gitpod/types/environments/automations/service_update_params.py @@ -0,0 +1,72 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo +from .service_phase import ServicePhase +from ...shared_params.runs_on import RunsOn +from ...shared_params.automation_trigger import AutomationTrigger + +__all__ = ["ServiceUpdateParams", "Metadata", "MetadataTriggeredBy", "Spec", "SpecCommands", "Status"] + + +class ServiceUpdateParams(TypedDict, total=False): + id: str + + metadata: Metadata + + spec: Spec + """Changing the spec of a service is a complex operation. + + The spec of a service can only be updated if the service is in a stopped state. + If the service is running, it must be stopped first. + """ + + status: Status + """Service status updates are only expected from the executing environment. + + As a client of this API you are not expected to provide this field. Updating + this field requires the `environmentservice:update_status` permission. + """ + + +class MetadataTriggeredBy(TypedDict, total=False): + trigger: Iterable[AutomationTrigger] + + +class Metadata(TypedDict, total=False): + description: Optional[str] + + name: Optional[str] + + triggered_by: Annotated[Optional[MetadataTriggeredBy], PropertyInfo(alias="triggeredBy")] + + +class SpecCommands(TypedDict, total=False): + ready: Optional[str] + + start: Optional[str] + + stop: Optional[str] + + +class Spec(TypedDict, total=False): + commands: Optional[SpecCommands] + + runs_on: Annotated[Optional[RunsOn], PropertyInfo(alias="runsOn")] + + +class Status(TypedDict, total=False): + failure_message: Annotated[Optional[str], PropertyInfo(alias="failureMessage")] + + log_url: Annotated[Optional[str], PropertyInfo(alias="logUrl")] + + output: Dict[str, str] + """setting an output field to empty string will unset it.""" + + phase: Optional[ServicePhase] + + session: Optional[str] diff --git a/src/gitpod/types/environments/automations/task_create_params.py b/src/gitpod/types/environments/automations/task_create_params.py new file mode 100644 index 0000000..5bb8916 --- /dev/null +++ b/src/gitpod/types/environments/automations/task_create_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo +from ...shared_params.task_spec import TaskSpec +from ...shared_params.task_metadata import TaskMetadata + +__all__ = ["TaskCreateParams"] + + +class TaskCreateParams(TypedDict, total=False): + depends_on: Annotated[List[str], PropertyInfo(alias="dependsOn")] + + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + + metadata: TaskMetadata + + spec: TaskSpec diff --git a/src/gitpod/types/environments/automations/task_create_response.py b/src/gitpod/types/environments/automations/task_create_response.py new file mode 100644 index 0000000..a00af2b --- /dev/null +++ b/src/gitpod/types/environments/automations/task_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel +from ...shared.task import Task + +__all__ = ["TaskCreateResponse"] + + +class TaskCreateResponse(BaseModel): + task: Task diff --git a/src/gitpod/types/environments/automations/task_delete_params.py b/src/gitpod/types/environments/automations/task_delete_params.py new file mode 100644 index 0000000..d1e4073 --- /dev/null +++ b/src/gitpod/types/environments/automations/task_delete_params.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 TypedDict + +__all__ = ["TaskDeleteParams"] + + +class TaskDeleteParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/environments/automations/task_list_params.py b/src/gitpod/types/environments/automations/task_list_params.py new file mode 100644 index 0000000..7afc694 --- /dev/null +++ b/src/gitpod/types/environments/automations/task_list_params.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["TaskListParams", "Filter", "Pagination"] + + +class TaskListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + """filter contains the filter options for listing tasks""" + + pagination: Pagination + """pagination contains the pagination options for listing tasks""" + + +class Filter(TypedDict, total=False): + environment_ids: Annotated[List[str], PropertyInfo(alias="environmentIds")] + """environment_ids filters the response to only tasks of these environments""" + + references: List[str] + """references filters the response to only services with these references""" + + task_ids: Annotated[List[str], PropertyInfo(alias="taskIds")] + """task_ids filters the response to only tasks with these IDs""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/environments/automations/task_retrieve_params.py b/src/gitpod/types/environments/automations/task_retrieve_params.py new file mode 100644 index 0000000..acd7ec7 --- /dev/null +++ b/src/gitpod/types/environments/automations/task_retrieve_params.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 TypedDict + +__all__ = ["TaskRetrieveParams"] + + +class TaskRetrieveParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/environments/automations/task_retrieve_response.py b/src/gitpod/types/environments/automations/task_retrieve_response.py new file mode 100644 index 0000000..546b7b0 --- /dev/null +++ b/src/gitpod/types/environments/automations/task_retrieve_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel +from ...shared.task import Task + +__all__ = ["TaskRetrieveResponse"] + + +class TaskRetrieveResponse(BaseModel): + task: Task diff --git a/src/gitpod/types/environments/automations/task_start_params.py b/src/gitpod/types/environments/automations/task_start_params.py new file mode 100644 index 0000000..e9b4703 --- /dev/null +++ b/src/gitpod/types/environments/automations/task_start_params.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 TypedDict + +__all__ = ["TaskStartParams"] + + +class TaskStartParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/environments/automations/task_start_response.py b/src/gitpod/types/environments/automations/task_start_response.py new file mode 100644 index 0000000..bb0fb10 --- /dev/null +++ b/src/gitpod/types/environments/automations/task_start_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from ...shared.task_execution import TaskExecution + +__all__ = ["TaskStartResponse"] + + +class TaskStartResponse(BaseModel): + task_execution: TaskExecution = FieldInfo(alias="taskExecution") diff --git a/src/gitpod/types/environments/automations/task_update_params.py b/src/gitpod/types/environments/automations/task_update_params.py new file mode 100644 index 0000000..4b0d59a --- /dev/null +++ b/src/gitpod/types/environments/automations/task_update_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Iterable, Optional +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo +from ...shared_params.runs_on import RunsOn +from ...shared_params.automation_trigger import AutomationTrigger + +__all__ = ["TaskUpdateParams", "Metadata", "MetadataTriggeredBy", "Spec"] + + +class TaskUpdateParams(TypedDict, total=False): + id: str + + depends_on: Annotated[List[str], PropertyInfo(alias="dependsOn")] + """dependencies specifies the IDs of the automations this task depends on.""" + + metadata: Metadata + + spec: Spec + + +class MetadataTriggeredBy(TypedDict, total=False): + trigger: Iterable[AutomationTrigger] + + +class Metadata(TypedDict, total=False): + description: Optional[str] + + name: Optional[str] + + triggered_by: Annotated[Optional[MetadataTriggeredBy], PropertyInfo(alias="triggeredBy")] + + +class Spec(TypedDict, total=False): + command: Optional[str] + + runs_on: Annotated[Optional[RunsOn], PropertyInfo(alias="runsOn")] diff --git a/src/gitpod/types/environments/automations/tasks/__init__.py b/src/gitpod/types/environments/automations/tasks/__init__.py new file mode 100644 index 0000000..f6dd9ac --- /dev/null +++ b/src/gitpod/types/environments/automations/tasks/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .execution_list_params import ExecutionListParams as ExecutionListParams +from .execution_stop_params import ExecutionStopParams as ExecutionStopParams +from .execution_retrieve_params import ExecutionRetrieveParams as ExecutionRetrieveParams +from .execution_retrieve_response import ExecutionRetrieveResponse as ExecutionRetrieveResponse diff --git a/src/gitpod/types/environments/automations/tasks/execution_list_params.py b/src/gitpod/types/environments/automations/tasks/execution_list_params.py new file mode 100644 index 0000000..0441fb5 --- /dev/null +++ b/src/gitpod/types/environments/automations/tasks/execution_list_params.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from ....._utils import PropertyInfo +from ....shared.task_execution_phase import TaskExecutionPhase + +__all__ = ["ExecutionListParams", "Filter", "Pagination"] + + +class ExecutionListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + """filter contains the filter options for listing task runs""" + + pagination: Pagination + """pagination contains the pagination options for listing task runs""" + + +class Filter(TypedDict, total=False): + environment_ids: Annotated[List[str], PropertyInfo(alias="environmentIds")] + """environment_ids filters the response to only task runs of these environments""" + + phases: List[TaskExecutionPhase] + """phases filters the response to only task runs in these phases""" + + task_ids: Annotated[List[str], PropertyInfo(alias="taskIds")] + """task_ids filters the response to only task runs of these tasks""" + + task_references: Annotated[List[str], PropertyInfo(alias="taskReferences")] + """task_references filters the response to only task runs with this reference""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/environments/automations/tasks/execution_retrieve_params.py b/src/gitpod/types/environments/automations/tasks/execution_retrieve_params.py new file mode 100644 index 0000000..85fa9fc --- /dev/null +++ b/src/gitpod/types/environments/automations/tasks/execution_retrieve_params.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 TypedDict + +__all__ = ["ExecutionRetrieveParams"] + + +class ExecutionRetrieveParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/environments/automations/tasks/execution_retrieve_response.py b/src/gitpod/types/environments/automations/tasks/execution_retrieve_response.py new file mode 100644 index 0000000..59483ce --- /dev/null +++ b/src/gitpod/types/environments/automations/tasks/execution_retrieve_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ....._models import BaseModel +from ....shared.task_execution import TaskExecution + +__all__ = ["ExecutionRetrieveResponse"] + + +class ExecutionRetrieveResponse(BaseModel): + task_execution: TaskExecution = FieldInfo(alias="taskExecution") diff --git a/src/gitpod/types/environments/automations/tasks/execution_stop_params.py b/src/gitpod/types/environments/automations/tasks/execution_stop_params.py new file mode 100644 index 0000000..9a5188e --- /dev/null +++ b/src/gitpod/types/environments/automations/tasks/execution_stop_params.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 TypedDict + +__all__ = ["ExecutionStopParams"] + + +class ExecutionStopParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/environments/automations_file_param.py b/src/gitpod/types/environments/automations_file_param.py new file mode 100644 index 0000000..e2c0a7e --- /dev/null +++ b/src/gitpod/types/environments/automations_file_param.py @@ -0,0 +1,77 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List +from typing_extensions import Literal, Annotated, TypedDict + +from ..._utils import PropertyInfo +from ..shared_params.runs_on import RunsOn + +__all__ = ["AutomationsFileParam", "Services", "ServicesCommands", "Tasks"] + + +class ServicesCommands(TypedDict, total=False): + ready: str + """ + ready is an optional command that is run repeatedly until it exits with a zero + exit code. If set, the service will first go into a Starting phase, and then + into a Running phase once the ready command exits with a zero exit code. + """ + + start: str + """ + start is the command to start and run the service. If start exits, the service + will transition to the following phase: + + - Stopped: if the exit code is 0 + - Failed: if the exit code is not 0 If the stop command is not set, the start + command will receive a SIGTERM signal when the service is requested to stop. + If it does not exit within 2 minutes, it will receive a SIGKILL signal. + """ + + stop: str + """ + stop is an optional command that runs when the service is requested to stop. If + set, instead of sending a SIGTERM signal to the start command, the stop command + will be run. Once the stop command exits, the start command will receive a + SIGKILL signal. If the stop command exits with a non-zero exit code, the service + will transition to the Failed phase. If the stop command does not exit within 2 + minutes, a SIGKILL signal will be sent to both the start and stop commands. + """ + + +class Services(TypedDict, total=False): + commands: ServicesCommands + + description: str + + name: str + + runs_on: Annotated[RunsOn, PropertyInfo(alias="runsOn")] + + triggered_by: Annotated[ + List[Literal["manual", "postEnvironmentStart", "postDevcontainerStart"]], PropertyInfo(alias="triggeredBy") + ] + + +class Tasks(TypedDict, total=False): + command: str + + depends_on: Annotated[List[str], PropertyInfo(alias="dependsOn")] + + description: str + + name: str + + runs_on: Annotated[RunsOn, PropertyInfo(alias="runsOn")] + + triggered_by: Annotated[ + List[Literal["manual", "postEnvironmentStart", "postDevcontainerStart"]], PropertyInfo(alias="triggeredBy") + ] + + +class AutomationsFileParam(TypedDict, total=False): + services: Dict[str, Services] + + tasks: Dict[str, Tasks] diff --git a/src/gitpod/types/environments/class_list_params.py b/src/gitpod/types/environments/class_list_params.py new file mode 100644 index 0000000..1abb82c --- /dev/null +++ b/src/gitpod/types/environments/class_list_params.py @@ -0,0 +1,68 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo +from ..runner_kind import RunnerKind +from ..runner_provider import RunnerProvider + +__all__ = ["ClassListParams", "Filter", "Pagination"] + + +class ClassListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + """pagination contains the pagination options for listing environment classes""" + + +class Filter(TypedDict, total=False): + can_create_environments: Annotated[Optional[bool], PropertyInfo(alias="canCreateEnvironments")] + """ + can_create_environments filters the response to only environment classes that + can be used to create new environments by the caller. Unlike enabled, which + indicates general availability, this ensures the caller only sees environment + classes they are allowed to use. + """ + + enabled: Optional[bool] + """ + enabled filters the response to only enabled or disabled environment classes. If + not set, all environment classes are returned. + """ + + runner_ids: Annotated[List[str], PropertyInfo(alias="runnerIds")] + """runner_ids filters the response to only EnvironmentClasses of these Runner IDs""" + + runner_kinds: Annotated[List[RunnerKind], PropertyInfo(alias="runnerKinds")] + """ + runner_kind filters the response to only environment classes from runners of + these kinds. + """ + + runner_providers: Annotated[List[RunnerProvider], PropertyInfo(alias="runnerProviders")] + """ + runner_providers filters the response to only environment classes from runners + of these providers. + """ + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/event_list_params.py b/src/gitpod/types/event_list_params.py new file mode 100644 index 0000000..f444df6 --- /dev/null +++ b/src/gitpod/types/event_list_params.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo +from .resource_type import ResourceType +from .shared.principal import Principal + +__all__ = ["EventListParams", "Filter", "Pagination"] + + +class EventListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + """pagination contains the pagination options for listing environments""" + + +class Filter(TypedDict, total=False): + actor_ids: Annotated[List[str], PropertyInfo(alias="actorIds")] + + actor_principals: Annotated[List[Principal], PropertyInfo(alias="actorPrincipals")] + + subject_ids: Annotated[List[str], PropertyInfo(alias="subjectIds")] + + subject_types: Annotated[List[ResourceType], PropertyInfo(alias="subjectTypes")] + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/event_list_response.py b/src/gitpod/types/event_list_response.py new file mode 100644 index 0000000..ce8fb8b --- /dev/null +++ b/src/gitpod/types/event_list_response.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .resource_type import ResourceType +from .shared.principal import Principal + +__all__ = ["EventListResponse"] + + +class EventListResponse(BaseModel): + id: Optional[str] = None + + action: Optional[str] = None + + actor_id: Optional[str] = FieldInfo(alias="actorId", default=None) + + actor_principal: Optional[Principal] = FieldInfo(alias="actorPrincipal", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + subject_id: Optional[str] = FieldInfo(alias="subjectId", default=None) + + subject_type: Optional[ResourceType] = FieldInfo(alias="subjectType", default=None) diff --git a/src/gitpod/types/event_watch_params.py b/src/gitpod/types/event_watch_params.py new file mode 100644 index 0000000..0465a09 --- /dev/null +++ b/src/gitpod/types/event_watch_params.py @@ -0,0 +1,24 @@ +# 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__ = ["EventWatchParams"] + + +class EventWatchParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """ + Environment scope produces events for the environment itself, all tasks, task + executions, and services associated with that environment. + """ + + organization: bool + """ + Organization scope produces events for all projects, runners and environments + the caller can see within their organization. No task, task execution or service + events are produed. + """ diff --git a/src/gitpod/types/event_watch_response.py b/src/gitpod/types/event_watch_response.py new file mode 100644 index 0000000..9780ee1 --- /dev/null +++ b/src/gitpod/types/event_watch_response.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .resource_type import ResourceType +from .resource_operation import ResourceOperation + +__all__ = ["EventWatchResponse"] + + +class EventWatchResponse(BaseModel): + operation: Optional[ResourceOperation] = None + + resource_id: Optional[str] = FieldInfo(alias="resourceId", default=None) + + resource_type: Optional[ResourceType] = FieldInfo(alias="resourceType", default=None) diff --git a/src/gitpod/types/gateway_info.py b/src/gitpod/types/gateway_info.py new file mode 100644 index 0000000..d8211a9 --- /dev/null +++ b/src/gitpod/types/gateway_info.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel +from .shared.gateway import Gateway + +__all__ = ["GatewayInfo"] + + +class GatewayInfo(BaseModel): + gateway: Optional[Gateway] = None + """Gateway represents a system gateway that provides access to services""" + + latency: Optional[str] = None + """latency is the round-trip time of the runner to the gateway in milliseconds.""" diff --git a/src/gitpod/types/gateway_list_params.py b/src/gitpod/types/gateway_list_params.py new file mode 100644 index 0000000..8afa467 --- /dev/null +++ b/src/gitpod/types/gateway_list_params.py @@ -0,0 +1,32 @@ +# 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__ = ["GatewayListParams", "Pagination"] + + +class GatewayListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + pagination: Pagination + """pagination contains the pagination options for listing gateways""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/group.py b/src/gitpod/types/group.py new file mode 100644 index 0000000..a98b80b --- /dev/null +++ b/src/gitpod/types/group.py @@ -0,0 +1,205 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["Group"] + + +class Group(BaseModel): + id: Optional[str] = None + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + name: Optional[str] = None + + organization_id: Optional[str] = FieldInfo(alias="organizationId", default=None) + + system_managed: Optional[bool] = FieldInfo(alias="systemManaged", default=None) + """system_managed indicates that this group is created by the system automatically""" + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ diff --git a/src/gitpod/types/group_list_params.py b/src/gitpod/types/group_list_params.py new file mode 100644 index 0000000..9b7e7e8 --- /dev/null +++ b/src/gitpod/types/group_list_params.py @@ -0,0 +1,32 @@ +# 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__ = ["GroupListParams", "Pagination"] + + +class GroupListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + pagination: Pagination + """pagination contains the pagination options for listing groups""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/id_token_version.py b/src/gitpod/types/id_token_version.py new file mode 100644 index 0000000..ecbfdba --- /dev/null +++ b/src/gitpod/types/id_token_version.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__ = ["IDTokenVersion"] + +IDTokenVersion: TypeAlias = Literal["ID_TOKEN_VERSION_UNSPECIFIED", "ID_TOKEN_VERSION_V1", "ID_TOKEN_VERSION_V2"] diff --git a/src/gitpod/types/identity_exchange_token_params.py b/src/gitpod/types/identity_exchange_token_params.py new file mode 100644 index 0000000..e9114bd --- /dev/null +++ b/src/gitpod/types/identity_exchange_token_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["IdentityExchangeTokenParams"] + + +class IdentityExchangeTokenParams(TypedDict, total=False): + exchange_token: Annotated[str, PropertyInfo(alias="exchangeToken")] + """exchange_token is the token to exchange""" diff --git a/src/gitpod/types/identity_exchange_token_response.py b/src/gitpod/types/identity_exchange_token_response.py new file mode 100644 index 0000000..c101adb --- /dev/null +++ b/src/gitpod/types/identity_exchange_token_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["IdentityExchangeTokenResponse"] + + +class IdentityExchangeTokenResponse(BaseModel): + access_token: Optional[str] = FieldInfo(alias="accessToken", default=None) + """access_token is the new access token""" diff --git a/src/gitpod/types/identity_get_authenticated_identity_params.py b/src/gitpod/types/identity_get_authenticated_identity_params.py new file mode 100644 index 0000000..2ed3b1f --- /dev/null +++ b/src/gitpod/types/identity_get_authenticated_identity_params.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 TypedDict + +__all__ = ["IdentityGetAuthenticatedIdentityParams"] + + +class IdentityGetAuthenticatedIdentityParams(TypedDict, total=False): + empty: bool diff --git a/src/gitpod/types/identity_get_authenticated_identity_response.py b/src/gitpod/types/identity_get_authenticated_identity_response.py new file mode 100644 index 0000000..f04ad09 --- /dev/null +++ b/src/gitpod/types/identity_get_authenticated_identity_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.subject import Subject + +__all__ = ["IdentityGetAuthenticatedIdentityResponse"] + + +class IdentityGetAuthenticatedIdentityResponse(BaseModel): + organization_id: Optional[str] = FieldInfo(alias="organizationId", default=None) + + subject: Optional[Subject] = None + """subject is the identity of the current user""" diff --git a/src/gitpod/types/identity_get_id_token_params.py b/src/gitpod/types/identity_get_id_token_params.py new file mode 100644 index 0000000..c5686ae --- /dev/null +++ b/src/gitpod/types/identity_get_id_token_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 import List +from typing_extensions import TypedDict + +from .id_token_version import IDTokenVersion + +__all__ = ["IdentityGetIDTokenParams"] + + +class IdentityGetIDTokenParams(TypedDict, total=False): + audience: List[str] + + version: IDTokenVersion + """version is the version of the ID token.""" diff --git a/src/gitpod/types/identity_get_id_token_response.py b/src/gitpod/types/identity_get_id_token_response.py new file mode 100644 index 0000000..e327e68 --- /dev/null +++ b/src/gitpod/types/identity_get_id_token_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["IdentityGetIDTokenResponse"] + + +class IdentityGetIDTokenResponse(BaseModel): + token: Optional[str] = None diff --git a/src/gitpod/types/invite_domains.py b/src/gitpod/types/invite_domains.py new file mode 100644 index 0000000..32a0c7f --- /dev/null +++ b/src/gitpod/types/invite_domains.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["InviteDomains"] + + +class InviteDomains(BaseModel): + domains: Optional[List[str]] = None + """domains is the list of domains that are allowed to join the organization""" diff --git a/src/gitpod/types/invite_domains_param.py b/src/gitpod/types/invite_domains_param.py new file mode 100644 index 0000000..d38601a --- /dev/null +++ b/src/gitpod/types/invite_domains_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import TypedDict + +__all__ = ["InviteDomainsParam"] + + +class InviteDomainsParam(TypedDict, total=False): + domains: List[str] + """domains is the list of domains that are allowed to join the organization""" diff --git a/src/gitpod/types/joinable_organization.py b/src/gitpod/types/joinable_organization.py new file mode 100644 index 0000000..a5b6cb6 --- /dev/null +++ b/src/gitpod/types/joinable_organization.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["JoinableOrganization"] + + +class JoinableOrganization(BaseModel): + organization_id: str = FieldInfo(alias="organizationId") + """organization_id is the id of the organization the user can join""" + + organization_name: str = FieldInfo(alias="organizationName") + """organization_name is the name of the organization the user can join""" + + organization_member_count: Optional[int] = FieldInfo(alias="organizationMemberCount", default=None) + """ + organization_member_count is the member count of the organization the user can + join + """ diff --git a/src/gitpod/types/log_level.py b/src/gitpod/types/log_level.py new file mode 100644 index 0000000..7f2abd1 --- /dev/null +++ b/src/gitpod/types/log_level.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LogLevel"] + +LogLevel: TypeAlias = Literal[ + "LOG_LEVEL_UNSPECIFIED", "LOG_LEVEL_DEBUG", "LOG_LEVEL_INFO", "LOG_LEVEL_WARN", "LOG_LEVEL_ERROR" +] diff --git a/src/gitpod/types/login_provider.py b/src/gitpod/types/login_provider.py new file mode 100644 index 0000000..e23ebd8 --- /dev/null +++ b/src/gitpod/types/login_provider.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["LoginProvider"] + + +class LoginProvider(BaseModel): + provider: str + """provider is the provider used by this login method, e.g. + + "github", "google", "custom" + """ + + login_url: Optional[str] = FieldInfo(alias="loginUrl", default=None) + """ + login_url is the URL to redirect the browser agent to for login, when provider + is "custom" + """ diff --git a/src/gitpod/types/metrics_configuration.py b/src/gitpod/types/metrics_configuration.py new file mode 100644 index 0000000..0f6a075 --- /dev/null +++ b/src/gitpod/types/metrics_configuration.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["MetricsConfiguration"] + + +class MetricsConfiguration(BaseModel): + enabled: Optional[bool] = None + """enabled indicates whether the runner should collect metrics""" + + password: Optional[str] = None + """password is the password to use for the metrics collector""" + + url: Optional[str] = None + """url is the URL of the metrics collector""" + + username: Optional[str] = None + """username is the username to use for the metrics collector""" diff --git a/src/gitpod/types/metrics_configuration_param.py b/src/gitpod/types/metrics_configuration_param.py new file mode 100644 index 0000000..252253e --- /dev/null +++ b/src/gitpod/types/metrics_configuration_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["MetricsConfigurationParam"] + + +class MetricsConfigurationParam(TypedDict, total=False): + enabled: bool + """enabled indicates whether the runner should collect metrics""" + + password: str + """password is the password to use for the metrics collector""" + + url: str + """url is the URL of the metrics collector""" + + username: str + """username is the username to use for the metrics collector""" diff --git a/src/gitpod/types/organization.py b/src/gitpod/types/organization.py new file mode 100644 index 0000000..9ecda14 --- /dev/null +++ b/src/gitpod/types/organization.py @@ -0,0 +1,207 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .invite_domains import InviteDomains +from .organization_tier import OrganizationTier + +__all__ = ["Organization"] + + +class Organization(BaseModel): + id: str + + created_at: datetime = FieldInfo(alias="createdAt") + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + name: str + + tier: OrganizationTier + """The tier of the organization - free or enterprise""" + + updated_at: datetime = FieldInfo(alias="updatedAt") + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + invite_domains: Optional[InviteDomains] = FieldInfo(alias="inviteDomains", default=None) diff --git a/src/gitpod/types/organization_create_params.py b/src/gitpod/types/organization_create_params.py new file mode 100644 index 0000000..8251342 --- /dev/null +++ b/src/gitpod/types/organization_create_params.py @@ -0,0 +1,26 @@ +# 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 + +__all__ = ["OrganizationCreateParams"] + + +class OrganizationCreateParams(TypedDict, total=False): + name: Required[str] + """name is the organization name""" + + invite_accounts_with_matching_domain: Annotated[bool, PropertyInfo(alias="inviteAccountsWithMatchingDomain")] + """ + Should other Accounts with the same domain be automatically invited to the + organization? + """ + + join_organization: Annotated[bool, PropertyInfo(alias="joinOrganization")] + """ + join_organization decides whether the Identity issuing this request joins the + org on creation + """ diff --git a/src/gitpod/types/organization_create_response.py b/src/gitpod/types/organization_create_response.py new file mode 100644 index 0000000..51cb8f7 --- /dev/null +++ b/src/gitpod/types/organization_create_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel +from .organization import Organization +from .organization_member import OrganizationMember + +__all__ = ["OrganizationCreateResponse"] + + +class OrganizationCreateResponse(BaseModel): + organization: Organization + """organization is the created organization""" + + member: Optional[OrganizationMember] = None + """member is the member that joined the org on creation. + + Only set if specified "join_organization" is "true" in the request. + """ diff --git a/src/gitpod/types/organization_delete_params.py b/src/gitpod/types/organization_delete_params.py new file mode 100644 index 0000000..8402335 --- /dev/null +++ b/src/gitpod/types/organization_delete_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["OrganizationDeleteParams"] + + +class OrganizationDeleteParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + """organization_id is the ID of the organization to delete""" diff --git a/src/gitpod/types/organization_join_params.py b/src/gitpod/types/organization_join_params.py new file mode 100644 index 0000000..25f8223 --- /dev/null +++ b/src/gitpod/types/organization_join_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 Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["OrganizationJoinParams"] + + +class OrganizationJoinParams(TypedDict, total=False): + invite_id: Annotated[str, PropertyInfo(alias="inviteId")] + """invite_id is the unique identifier of the invite to join the organization.""" + + organization_id: Annotated[str, PropertyInfo(alias="organizationId")] + """organization_id is the unique identifier of the Organization to join.""" diff --git a/src/gitpod/types/organization_join_response.py b/src/gitpod/types/organization_join_response.py new file mode 100644 index 0000000..78e8ff9 --- /dev/null +++ b/src/gitpod/types/organization_join_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .organization_member import OrganizationMember + +__all__ = ["OrganizationJoinResponse"] + + +class OrganizationJoinResponse(BaseModel): + member: OrganizationMember + """member is the member that was created by joining the organization.""" diff --git a/src/gitpod/types/organization_leave_params.py b/src/gitpod/types/organization_leave_params.py new file mode 100644 index 0000000..f875644 --- /dev/null +++ b/src/gitpod/types/organization_leave_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["OrganizationLeaveParams"] + + +class OrganizationLeaveParams(TypedDict, total=False): + user_id: Required[Annotated[str, PropertyInfo(alias="userId")]] diff --git a/src/gitpod/types/organization_list_members_params.py b/src/gitpod/types/organization_list_members_params.py new file mode 100644 index 0000000..aa85f58 --- /dev/null +++ b/src/gitpod/types/organization_list_members_params.py @@ -0,0 +1,35 @@ +# 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 + +__all__ = ["OrganizationListMembersParams", "Pagination"] + + +class OrganizationListMembersParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + """organization_id is the ID of the organization to list members for""" + + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + pagination: Pagination + """pagination contains the pagination options for listing members""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/organization_member.py b/src/gitpod/types/organization_member.py new file mode 100644 index 0000000..6745f0b --- /dev/null +++ b/src/gitpod/types/organization_member.py @@ -0,0 +1,121 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.user_status import UserStatus +from .shared.organization_role import OrganizationRole + +__all__ = ["OrganizationMember"] + + +class OrganizationMember(BaseModel): + email: str + + full_name: str = FieldInfo(alias="fullName") + + login_provider: str = FieldInfo(alias="loginProvider") + """login_provider is the login provider the user uses to sign in""" + + member_since: datetime = FieldInfo(alias="memberSince") + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + role: OrganizationRole + + status: UserStatus + + user_id: str = FieldInfo(alias="userId") + + avatar_url: Optional[str] = FieldInfo(alias="avatarUrl", default=None) diff --git a/src/gitpod/types/organization_retrieve_params.py b/src/gitpod/types/organization_retrieve_params.py new file mode 100644 index 0000000..e81f1f3 --- /dev/null +++ b/src/gitpod/types/organization_retrieve_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["OrganizationRetrieveParams"] + + +class OrganizationRetrieveParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + """organization_id is the unique identifier of the Organization to retreive.""" diff --git a/src/gitpod/types/organization_retrieve_response.py b/src/gitpod/types/organization_retrieve_response.py new file mode 100644 index 0000000..b557f52 --- /dev/null +++ b/src/gitpod/types/organization_retrieve_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .organization import Organization + +__all__ = ["OrganizationRetrieveResponse"] + + +class OrganizationRetrieveResponse(BaseModel): + organization: Organization + """organization is the requested organization""" diff --git a/src/gitpod/types/organization_set_role_params.py b/src/gitpod/types/organization_set_role_params.py new file mode 100644 index 0000000..9c9d4b8 --- /dev/null +++ b/src/gitpod/types/organization_set_role_params.py @@ -0,0 +1,18 @@ +# 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.organization_role import OrganizationRole + +__all__ = ["OrganizationSetRoleParams"] + + +class OrganizationSetRoleParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + + user_id: Required[Annotated[str, PropertyInfo(alias="userId")]] + + role: OrganizationRole diff --git a/src/gitpod/types/organization_tier.py b/src/gitpod/types/organization_tier.py new file mode 100644 index 0000000..ea000b2 --- /dev/null +++ b/src/gitpod/types/organization_tier.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["OrganizationTier"] + +OrganizationTier: TypeAlias = Literal[ + "ORGANIZATION_TIER_UNSPECIFIED", "ORGANIZATION_TIER_FREE", "ORGANIZATION_TIER_ENTERPRISE" +] diff --git a/src/gitpod/types/organization_update_params.py b/src/gitpod/types/organization_update_params.py new file mode 100644 index 0000000..b6018bf --- /dev/null +++ b/src/gitpod/types/organization_update_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo +from .invite_domains_param import InviteDomainsParam + +__all__ = ["OrganizationUpdateParams"] + + +class OrganizationUpdateParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + """organization_id is the ID of the organization to update the settings for.""" + + invite_domains: Annotated[Optional[InviteDomainsParam], PropertyInfo(alias="inviteDomains")] + """invite_domains is the domain allowlist of the organization""" + + name: Optional[str] + """name is the new name of the organization""" diff --git a/src/gitpod/types/organization_update_response.py b/src/gitpod/types/organization_update_response.py new file mode 100644 index 0000000..d904634 --- /dev/null +++ b/src/gitpod/types/organization_update_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .organization import Organization + +__all__ = ["OrganizationUpdateResponse"] + + +class OrganizationUpdateResponse(BaseModel): + organization: Organization + """organization is the updated organization""" diff --git a/src/gitpod/types/organizations/__init__.py b/src/gitpod/types/organizations/__init__.py new file mode 100644 index 0000000..edd5451 --- /dev/null +++ b/src/gitpod/types/organizations/__init__.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .provider_type import ProviderType as ProviderType +from .sso_configuration import SSOConfiguration as SSOConfiguration +from .domain_verification import DomainVerification as DomainVerification +from .organization_invite import OrganizationInvite as OrganizationInvite +from .invite_create_params import InviteCreateParams as InviteCreateParams +from .policy_update_params import PolicyUpdateParams as PolicyUpdateParams +from .organization_policies import OrganizationPolicies as OrganizationPolicies +from .invite_create_response import InviteCreateResponse as InviteCreateResponse +from .invite_retrieve_params import InviteRetrieveParams as InviteRetrieveParams +from .policy_retrieve_params import PolicyRetrieveParams as PolicyRetrieveParams +from .sso_configuration_state import SSOConfigurationState as SSOConfigurationState +from .invite_retrieve_response import InviteRetrieveResponse as InviteRetrieveResponse +from .policy_retrieve_response import PolicyRetrieveResponse as PolicyRetrieveResponse +from .domain_verification_state import DomainVerificationState as DomainVerificationState +from .invite_get_summary_params import InviteGetSummaryParams as InviteGetSummaryParams +from .invite_get_summary_response import InviteGetSummaryResponse as InviteGetSummaryResponse +from .sso_configuration_list_params import SSOConfigurationListParams as SSOConfigurationListParams +from .domain_verification_list_params import DomainVerificationListParams as DomainVerificationListParams +from .sso_configuration_create_params import SSOConfigurationCreateParams as SSOConfigurationCreateParams +from .sso_configuration_delete_params import SSOConfigurationDeleteParams as SSOConfigurationDeleteParams +from .sso_configuration_update_params import SSOConfigurationUpdateParams as SSOConfigurationUpdateParams +from .domain_verification_create_params import DomainVerificationCreateParams as DomainVerificationCreateParams +from .domain_verification_delete_params import DomainVerificationDeleteParams as DomainVerificationDeleteParams +from .domain_verification_verify_params import DomainVerificationVerifyParams as DomainVerificationVerifyParams +from .sso_configuration_create_response import SSOConfigurationCreateResponse as SSOConfigurationCreateResponse +from .sso_configuration_retrieve_params import SSOConfigurationRetrieveParams as SSOConfigurationRetrieveParams +from .domain_verification_create_response import DomainVerificationCreateResponse as DomainVerificationCreateResponse +from .domain_verification_retrieve_params import DomainVerificationRetrieveParams as DomainVerificationRetrieveParams +from .domain_verification_verify_response import DomainVerificationVerifyResponse as DomainVerificationVerifyResponse +from .sso_configuration_retrieve_response import SSOConfigurationRetrieveResponse as SSOConfigurationRetrieveResponse +from .domain_verification_retrieve_response import ( + DomainVerificationRetrieveResponse as DomainVerificationRetrieveResponse, +) diff --git a/src/gitpod/types/organizations/domain_verification.py b/src/gitpod/types/organizations/domain_verification.py new file mode 100644 index 0000000..3d2e32a --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification.py @@ -0,0 +1,207 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .domain_verification_state import DomainVerificationState + +__all__ = ["DomainVerification"] + + +class DomainVerification(BaseModel): + id: str + + domain: str + + organization_id: str = FieldInfo(alias="organizationId") + + state: DomainVerificationState + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + verification_token: Optional[str] = FieldInfo(alias="verificationToken", default=None) + + verified_at: Optional[datetime] = FieldInfo(alias="verifiedAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ diff --git a/src/gitpod/types/organizations/domain_verification_create_params.py b/src/gitpod/types/organizations/domain_verification_create_params.py new file mode 100644 index 0000000..cfd882a --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_create_params.py @@ -0,0 +1,15 @@ +# 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 + +__all__ = ["DomainVerificationCreateParams"] + + +class DomainVerificationCreateParams(TypedDict, total=False): + domain: Required[str] + + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] diff --git a/src/gitpod/types/organizations/domain_verification_create_response.py b/src/gitpod/types/organizations/domain_verification_create_response.py new file mode 100644 index 0000000..3429a61 --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_create_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .domain_verification import DomainVerification + +__all__ = ["DomainVerificationCreateResponse"] + + +class DomainVerificationCreateResponse(BaseModel): + domain_verification: DomainVerification = FieldInfo(alias="domainVerification") diff --git a/src/gitpod/types/organizations/domain_verification_delete_params.py b/src/gitpod/types/organizations/domain_verification_delete_params.py new file mode 100644 index 0000000..d8f6a81 --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_delete_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["DomainVerificationDeleteParams"] + + +class DomainVerificationDeleteParams(TypedDict, total=False): + domain_verification_id: Required[Annotated[str, PropertyInfo(alias="domainVerificationId")]] diff --git a/src/gitpod/types/organizations/domain_verification_list_params.py b/src/gitpod/types/organizations/domain_verification_list_params.py new file mode 100644 index 0000000..26573f6 --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_list_params.py @@ -0,0 +1,33 @@ +# 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 + +__all__ = ["DomainVerificationListParams", "Pagination"] + + +class DomainVerificationListParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + pagination: Pagination + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/organizations/domain_verification_retrieve_params.py b/src/gitpod/types/organizations/domain_verification_retrieve_params.py new file mode 100644 index 0000000..7910e1f --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_retrieve_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["DomainVerificationRetrieveParams"] + + +class DomainVerificationRetrieveParams(TypedDict, total=False): + domain_verification_id: Required[Annotated[str, PropertyInfo(alias="domainVerificationId")]] diff --git a/src/gitpod/types/organizations/domain_verification_retrieve_response.py b/src/gitpod/types/organizations/domain_verification_retrieve_response.py new file mode 100644 index 0000000..7f8d7e1 --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_retrieve_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .domain_verification import DomainVerification + +__all__ = ["DomainVerificationRetrieveResponse"] + + +class DomainVerificationRetrieveResponse(BaseModel): + domain_verification: DomainVerification = FieldInfo(alias="domainVerification") diff --git a/src/gitpod/types/organizations/domain_verification_state.py b/src/gitpod/types/organizations/domain_verification_state.py new file mode 100644 index 0000000..cc7a6d8 --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_state.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["DomainVerificationState"] + +DomainVerificationState: TypeAlias = Literal[ + "DOMAIN_VERIFICATION_STATE_UNSPECIFIED", "DOMAIN_VERIFICATION_STATE_PENDING", "DOMAIN_VERIFICATION_STATE_VERIFIED" +] diff --git a/src/gitpod/types/organizations/domain_verification_verify_params.py b/src/gitpod/types/organizations/domain_verification_verify_params.py new file mode 100644 index 0000000..1f0c3e8 --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_verify_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["DomainVerificationVerifyParams"] + + +class DomainVerificationVerifyParams(TypedDict, total=False): + domain_verification_id: Required[Annotated[str, PropertyInfo(alias="domainVerificationId")]] diff --git a/src/gitpod/types/organizations/domain_verification_verify_response.py b/src/gitpod/types/organizations/domain_verification_verify_response.py new file mode 100644 index 0000000..307656e --- /dev/null +++ b/src/gitpod/types/organizations/domain_verification_verify_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .domain_verification import DomainVerification + +__all__ = ["DomainVerificationVerifyResponse"] + + +class DomainVerificationVerifyResponse(BaseModel): + domain_verification: DomainVerification = FieldInfo(alias="domainVerification") diff --git a/src/gitpod/types/organizations/invite_create_params.py b/src/gitpod/types/organizations/invite_create_params.py new file mode 100644 index 0000000..32455ba --- /dev/null +++ b/src/gitpod/types/organizations/invite_create_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["InviteCreateParams"] + + +class InviteCreateParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] diff --git a/src/gitpod/types/organizations/invite_create_response.py b/src/gitpod/types/organizations/invite_create_response.py new file mode 100644 index 0000000..9a00dac --- /dev/null +++ b/src/gitpod/types/organizations/invite_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .organization_invite import OrganizationInvite + +__all__ = ["InviteCreateResponse"] + + +class InviteCreateResponse(BaseModel): + invite: OrganizationInvite diff --git a/src/gitpod/types/organizations/invite_get_summary_params.py b/src/gitpod/types/organizations/invite_get_summary_params.py new file mode 100644 index 0000000..5b57656 --- /dev/null +++ b/src/gitpod/types/organizations/invite_get_summary_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["InviteGetSummaryParams"] + + +class InviteGetSummaryParams(TypedDict, total=False): + invite_id: Required[Annotated[str, PropertyInfo(alias="inviteId")]] diff --git a/src/gitpod/types/organizations/invite_get_summary_response.py b/src/gitpod/types/organizations/invite_get_summary_response.py new file mode 100644 index 0000000..786ae36 --- /dev/null +++ b/src/gitpod/types/organizations/invite_get_summary_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["InviteGetSummaryResponse"] + + +class InviteGetSummaryResponse(BaseModel): + organization_id: str = FieldInfo(alias="organizationId") + + organization_member_count: Optional[int] = FieldInfo(alias="organizationMemberCount", default=None) + + organization_name: Optional[str] = FieldInfo(alias="organizationName", default=None) diff --git a/src/gitpod/types/organizations/invite_retrieve_params.py b/src/gitpod/types/organizations/invite_retrieve_params.py new file mode 100644 index 0000000..a181214 --- /dev/null +++ b/src/gitpod/types/organizations/invite_retrieve_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["InviteRetrieveParams"] + + +class InviteRetrieveParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] diff --git a/src/gitpod/types/organizations/invite_retrieve_response.py b/src/gitpod/types/organizations/invite_retrieve_response.py new file mode 100644 index 0000000..d00f343 --- /dev/null +++ b/src/gitpod/types/organizations/invite_retrieve_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .organization_invite import OrganizationInvite + +__all__ = ["InviteRetrieveResponse"] + + +class InviteRetrieveResponse(BaseModel): + invite: OrganizationInvite diff --git a/src/gitpod/types/organizations/organization_invite.py b/src/gitpod/types/organizations/organization_invite.py new file mode 100644 index 0000000..b33984a --- /dev/null +++ b/src/gitpod/types/organizations/organization_invite.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["OrganizationInvite"] + + +class OrganizationInvite(BaseModel): + invite_id: str = FieldInfo(alias="inviteId") + """ + invite_id is the unique identifier of the invite to join the organization. Use + JoinOrganization with this ID to join the organization. + """ diff --git a/src/gitpod/types/organizations/organization_policies.py b/src/gitpod/types/organizations/organization_policies.py new file mode 100644 index 0000000..673c756 --- /dev/null +++ b/src/gitpod/types/organizations/organization_policies.py @@ -0,0 +1,72 @@ +# 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__ = ["OrganizationPolicies"] + + +class OrganizationPolicies(BaseModel): + allowed_editor_ids: List[str] = FieldInfo(alias="allowedEditorIds") + """ + allowed_editor_ids is the list of editor IDs that are allowed to be used in the + organization + """ + + allow_local_runners: bool = FieldInfo(alias="allowLocalRunners") + """ + allow_local_runners controls whether local runners are allowed to be used in the + organization + """ + + default_editor_id: str = FieldInfo(alias="defaultEditorId") + """ + default_editor_id is the default editor ID to be used when a user doesn't + specify one + """ + + default_environment_image: str = FieldInfo(alias="defaultEnvironmentImage") + """ + default_environment_image is the default container image when none is defined in + repo + """ + + maximum_environments_per_user: str = FieldInfo(alias="maximumEnvironmentsPerUser") + """ + maximum_environments_per_user limits total environments (running or stopped) per + user + """ + + maximum_running_environments_per_user: str = FieldInfo(alias="maximumRunningEnvironmentsPerUser") + """ + maximum_running_environments_per_user limits simultaneously running environments + per user + """ + + members_create_projects: bool = FieldInfo(alias="membersCreateProjects") + """members_create_projects controls whether members can create projects""" + + members_require_projects: bool = FieldInfo(alias="membersRequireProjects") + """ + members_require_projects controls whether environments can only be created from + projects by non-admin users + """ + + organization_id: str = FieldInfo(alias="organizationId") + """organization_id is the ID of the organization""" + + port_sharing_disabled: bool = FieldInfo(alias="portSharingDisabled") + """ + port_sharing_disabled controls whether port sharing is disabled in the + organization + """ + + maximum_environment_timeout: Optional[str] = FieldInfo(alias="maximumEnvironmentTimeout", default=None) + """ + maximum_environment_timeout controls the maximum timeout allowed for + environments in seconds. 0 means no limit (never). Minimum duration is 30 + minutes. + """ diff --git a/src/gitpod/types/organizations/policy_retrieve_params.py b/src/gitpod/types/organizations/policy_retrieve_params.py new file mode 100644 index 0000000..8c54248 --- /dev/null +++ b/src/gitpod/types/organizations/policy_retrieve_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["PolicyRetrieveParams"] + + +class PolicyRetrieveParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + """organization_id is the ID of the organization to retrieve policies for""" diff --git a/src/gitpod/types/organizations/policy_retrieve_response.py b/src/gitpod/types/organizations/policy_retrieve_response.py new file mode 100644 index 0000000..c54a1e7 --- /dev/null +++ b/src/gitpod/types/organizations/policy_retrieve_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .organization_policies import OrganizationPolicies + +__all__ = ["PolicyRetrieveResponse"] + + +class PolicyRetrieveResponse(BaseModel): + policies: OrganizationPolicies diff --git a/src/gitpod/types/organizations/policy_update_params.py b/src/gitpod/types/organizations/policy_update_params.py new file mode 100644 index 0000000..ca6b8ab --- /dev/null +++ b/src/gitpod/types/organizations/policy_update_params.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["PolicyUpdateParams"] + + +class PolicyUpdateParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + """organization_id is the ID of the organization to update policies for""" + + allowed_editor_ids: Annotated[List[str], PropertyInfo(alias="allowedEditorIds")] + """ + allowed_editor_ids is the list of editor IDs that are allowed to be used in the + organization + """ + + allow_local_runners: Annotated[Optional[bool], PropertyInfo(alias="allowLocalRunners")] + """ + allow_local_runners controls whether local runners are allowed to be used in the + organization + """ + + default_editor_id: Annotated[Optional[str], PropertyInfo(alias="defaultEditorId")] + """ + default_editor_id is the default editor ID to be used when a user doesn't + specify one + """ + + default_environment_image: Annotated[Optional[str], PropertyInfo(alias="defaultEnvironmentImage")] + """ + default_environment_image is the default container image when none is defined in + repo + """ + + maximum_environments_per_user: Annotated[Optional[str], PropertyInfo(alias="maximumEnvironmentsPerUser")] + """ + maximum_environments_per_user limits total environments (running or stopped) per + user + """ + + maximum_environment_timeout: Annotated[Optional[str], PropertyInfo(alias="maximumEnvironmentTimeout")] + """ + maximum_environment_timeout controls the maximum timeout allowed for + environments in seconds. 0 means no limit (never). Minimum duration is 30 + minutes. + """ + + maximum_running_environments_per_user: Annotated[ + Optional[str], PropertyInfo(alias="maximumRunningEnvironmentsPerUser") + ] + """ + maximum_running_environments_per_user limits simultaneously running environments + per user + """ + + members_create_projects: Annotated[Optional[bool], PropertyInfo(alias="membersCreateProjects")] + """members_create_projects controls whether members can create projects""" + + members_require_projects: Annotated[Optional[bool], PropertyInfo(alias="membersRequireProjects")] + """ + members_require_projects controls whether environments can only be created from + projects by non-admin users + """ + + port_sharing_disabled: Annotated[Optional[bool], PropertyInfo(alias="portSharingDisabled")] + """ + port_sharing_disabled controls whether port sharing is disabled in the + organization + """ diff --git a/src/gitpod/types/organizations/provider_type.py b/src/gitpod/types/organizations/provider_type.py new file mode 100644 index 0000000..a5691eb --- /dev/null +++ b/src/gitpod/types/organizations/provider_type.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__ = ["ProviderType"] + +ProviderType: TypeAlias = Literal["PROVIDER_TYPE_UNSPECIFIED", "PROVIDER_TYPE_BUILTIN", "PROVIDER_TYPE_CUSTOM"] diff --git a/src/gitpod/types/organizations/sso_configuration.py b/src/gitpod/types/organizations/sso_configuration.py new file mode 100644 index 0000000..4ae9912 --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .provider_type import ProviderType +from .sso_configuration_state import SSOConfigurationState + +__all__ = ["SSOConfiguration"] + + +class SSOConfiguration(BaseModel): + id: str + """id is the unique identifier of the SSO configuration""" + + issuer_url: str = FieldInfo(alias="issuerUrl") + """issuer_url is the URL of the IdP issuer""" + + organization_id: str = FieldInfo(alias="organizationId") + + provider_type: ProviderType = FieldInfo(alias="providerType") + """provider_type defines the type of the SSO configuration""" + + state: SSOConfigurationState + """state is the state of the SSO configuration""" + + claims: Optional[Dict[str, str]] = None + """claims are key/value pairs that defines a mapping of claims issued by the IdP.""" + + client_id: Optional[str] = FieldInfo(alias="clientId", default=None) + """client_id is the client ID of the OIDC application set on the IdP""" + + email_domain: Optional[str] = FieldInfo(alias="emailDomain", default=None) diff --git a/src/gitpod/types/organizations/sso_configuration_create_params.py b/src/gitpod/types/organizations/sso_configuration_create_params.py new file mode 100644 index 0000000..cd14f5c --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration_create_params.py @@ -0,0 +1,25 @@ +# 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 + +__all__ = ["SSOConfigurationCreateParams"] + + +class SSOConfigurationCreateParams(TypedDict, total=False): + client_id: Required[Annotated[str, PropertyInfo(alias="clientId")]] + """client_id is the client ID of the OIDC application set on the IdP""" + + client_secret: Required[Annotated[str, PropertyInfo(alias="clientSecret")]] + """client_secret is the client secret of the OIDC application set on the IdP""" + + email_domain: Required[Annotated[str, PropertyInfo(alias="emailDomain")]] + """email_domain is the domain that is allowed to sign in to the organization""" + + issuer_url: Required[Annotated[str, PropertyInfo(alias="issuerUrl")]] + """issuer_url is the URL of the IdP issuer""" + + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] diff --git a/src/gitpod/types/organizations/sso_configuration_create_response.py b/src/gitpod/types/organizations/sso_configuration_create_response.py new file mode 100644 index 0000000..7e85bbe --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration_create_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .sso_configuration import SSOConfiguration + +__all__ = ["SSOConfigurationCreateResponse"] + + +class SSOConfigurationCreateResponse(BaseModel): + sso_configuration: SSOConfiguration = FieldInfo(alias="ssoConfiguration") + """sso_configuration is the created SSO configuration""" diff --git a/src/gitpod/types/organizations/sso_configuration_delete_params.py b/src/gitpod/types/organizations/sso_configuration_delete_params.py new file mode 100644 index 0000000..0e3f7b0 --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration_delete_params.py @@ -0,0 +1,13 @@ +# 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 + +__all__ = ["SSOConfigurationDeleteParams"] + + +class SSOConfigurationDeleteParams(TypedDict, total=False): + sso_configuration_id: Required[Annotated[str, PropertyInfo(alias="ssoConfigurationId")]] diff --git a/src/gitpod/types/organizations/sso_configuration_list_params.py b/src/gitpod/types/organizations/sso_configuration_list_params.py new file mode 100644 index 0000000..1f4b3a6 --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration_list_params.py @@ -0,0 +1,34 @@ +# 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 + +__all__ = ["SSOConfigurationListParams", "Pagination"] + + +class SSOConfigurationListParams(TypedDict, total=False): + organization_id: Required[Annotated[str, PropertyInfo(alias="organizationId")]] + """organization_id is the ID of the organization to list SSO configurations for.""" + + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + pagination: Pagination + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/organizations/sso_configuration_retrieve_params.py b/src/gitpod/types/organizations/sso_configuration_retrieve_params.py new file mode 100644 index 0000000..25aa634 --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration_retrieve_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["SSOConfigurationRetrieveParams"] + + +class SSOConfigurationRetrieveParams(TypedDict, total=False): + sso_configuration_id: Required[Annotated[str, PropertyInfo(alias="ssoConfigurationId")]] + """sso_configuration_id is the ID of the SSO configuration to get""" diff --git a/src/gitpod/types/organizations/sso_configuration_retrieve_response.py b/src/gitpod/types/organizations/sso_configuration_retrieve_response.py new file mode 100644 index 0000000..c5e0bd3 --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration_retrieve_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .sso_configuration import SSOConfiguration + +__all__ = ["SSOConfigurationRetrieveResponse"] + + +class SSOConfigurationRetrieveResponse(BaseModel): + sso_configuration: SSOConfiguration = FieldInfo(alias="ssoConfiguration") + """sso_configuration is the SSO configuration identified by the ID""" diff --git a/src/gitpod/types/organizations/sso_configuration_state.py b/src/gitpod/types/organizations/sso_configuration_state.py new file mode 100644 index 0000000..e866445 --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration_state.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["SSOConfigurationState"] + +SSOConfigurationState: TypeAlias = Literal[ + "SSO_CONFIGURATION_STATE_UNSPECIFIED", "SSO_CONFIGURATION_STATE_INACTIVE", "SSO_CONFIGURATION_STATE_ACTIVE" +] diff --git a/src/gitpod/types/organizations/sso_configuration_update_params.py b/src/gitpod/types/organizations/sso_configuration_update_params.py new file mode 100644 index 0000000..4af2dab --- /dev/null +++ b/src/gitpod/types/organizations/sso_configuration_update_params.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, Optional +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo +from .sso_configuration_state import SSOConfigurationState + +__all__ = ["SSOConfigurationUpdateParams"] + + +class SSOConfigurationUpdateParams(TypedDict, total=False): + sso_configuration_id: Required[Annotated[str, PropertyInfo(alias="ssoConfigurationId")]] + """sso_configuration_id is the ID of the SSO configuration to update""" + + claims: Dict[str, str] + """claims are key/value pairs that defines a mapping of claims issued by the IdP.""" + + client_id: Annotated[Optional[str], PropertyInfo(alias="clientId")] + """client_id is the client ID of the SSO provider""" + + client_secret: Annotated[Optional[str], PropertyInfo(alias="clientSecret")] + """client_secret is the client secret of the SSO provider""" + + email_domain: Annotated[Optional[str], PropertyInfo(alias="emailDomain")] + + issuer_url: Annotated[Optional[str], PropertyInfo(alias="issuerUrl")] + """issuer_url is the URL of the IdP issuer""" + + state: Optional[SSOConfigurationState] + """state is the state of the SSO configuration""" diff --git a/src/gitpod/types/project.py b/src/gitpod/types/project.py new file mode 100644 index 0000000..80e2586 --- /dev/null +++ b/src/gitpod/types/project.py @@ -0,0 +1,56 @@ +# 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 +from .shared.subject import Subject +from .project_metadata import ProjectMetadata +from .environment_initializer import EnvironmentInitializer +from .project_environment_class import ProjectEnvironmentClass + +__all__ = ["Project", "UsedBy"] + + +class UsedBy(BaseModel): + subjects: Optional[List[Subject]] = None + """ + Subjects are the 10 most recent subjects who have used the project to create an + environment + """ + + total_subjects: Optional[int] = FieldInfo(alias="totalSubjects", default=None) + """Total number of unique subjects who have used the project""" + + +class Project(BaseModel): + environment_class: ProjectEnvironmentClass = FieldInfo(alias="environmentClass") + + id: Optional[str] = None + """id is the unique identifier for the project""" + + automations_file_path: Optional[str] = FieldInfo(alias="automationsFilePath", default=None) + """ + automations_file_path is the path to the automations file relative to the repo + root + """ + + devcontainer_file_path: Optional[str] = FieldInfo(alias="devcontainerFilePath", default=None) + """ + devcontainer_file_path is the path to the devcontainer file relative to the repo + root + """ + + initializer: Optional[EnvironmentInitializer] = None + """initializer is the content initializer""" + + metadata: Optional[ProjectMetadata] = None + + technical_description: Optional[str] = FieldInfo(alias="technicalDescription", default=None) + """ + technical_description is a detailed technical description of the project This + field is not returned by default in GetProject or ListProjects responses + """ + + used_by: Optional[UsedBy] = FieldInfo(alias="usedBy", default=None) diff --git a/src/gitpod/types/project_create_from_environment_params.py b/src/gitpod/types/project_create_from_environment_params.py new file mode 100644 index 0000000..17da3e4 --- /dev/null +++ b/src/gitpod/types/project_create_from_environment_params.py @@ -0,0 +1,16 @@ +# 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__ = ["ProjectCreateFromEnvironmentParams"] + + +class ProjectCreateFromEnvironmentParams(TypedDict, total=False): + environment_id: Annotated[str, PropertyInfo(alias="environmentId")] + """environment_id specifies the environment identifier""" + + name: str diff --git a/src/gitpod/types/project_create_from_environment_response.py b/src/gitpod/types/project_create_from_environment_response.py new file mode 100644 index 0000000..5076ce2 --- /dev/null +++ b/src/gitpod/types/project_create_from_environment_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .project import Project +from .._models import BaseModel + +__all__ = ["ProjectCreateFromEnvironmentResponse"] + + +class ProjectCreateFromEnvironmentResponse(BaseModel): + project: Optional[Project] = None diff --git a/src/gitpod/types/project_create_params.py b/src/gitpod/types/project_create_params.py new file mode 100644 index 0000000..ff3b8b2 --- /dev/null +++ b/src/gitpod/types/project_create_params.py @@ -0,0 +1,46 @@ +# 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 .environment_initializer_param import EnvironmentInitializerParam +from .project_environment_class_param import ProjectEnvironmentClassParam + +__all__ = ["ProjectCreateParams"] + + +class ProjectCreateParams(TypedDict, total=False): + environment_class: Required[Annotated[ProjectEnvironmentClassParam, PropertyInfo(alias="environmentClass")]] + + initializer: Required[EnvironmentInitializerParam] + """initializer is the content initializer""" + + automations_file_path: Annotated[str, PropertyInfo(alias="automationsFilePath")] + """ + automations_file_path is the path to the automations file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + devcontainer_file_path: Annotated[str, PropertyInfo(alias="devcontainerFilePath")] + """ + devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + name: str + + technical_description: Annotated[str, PropertyInfo(alias="technicalDescription")] + """ + technical_description is a detailed technical description of the project This + field is not returned by default in GetProject or ListProjects responses 8KB max + """ diff --git a/src/gitpod/types/project_create_response.py b/src/gitpod/types/project_create_response.py new file mode 100644 index 0000000..81a0d7e --- /dev/null +++ b/src/gitpod/types/project_create_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .project import Project +from .._models import BaseModel + +__all__ = ["ProjectCreateResponse"] + + +class ProjectCreateResponse(BaseModel): + project: Optional[Project] = None diff --git a/src/gitpod/types/project_delete_params.py b/src/gitpod/types/project_delete_params.py new file mode 100644 index 0000000..8e7e188 --- /dev/null +++ b/src/gitpod/types/project_delete_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["ProjectDeleteParams"] + + +class ProjectDeleteParams(TypedDict, total=False): + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """project_id specifies the project identifier""" diff --git a/src/gitpod/types/project_environment_class.py b/src/gitpod/types/project_environment_class.py new file mode 100644 index 0000000..a969845 --- /dev/null +++ b/src/gitpod/types/project_environment_class.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["ProjectEnvironmentClass"] + + +class ProjectEnvironmentClass(BaseModel): + environment_class_id: Optional[str] = FieldInfo(alias="environmentClassId", default=None) + """Use a fixed environment class on a given Runner. + + This cannot be a local runner's environment class. + """ + + local_runner: Optional[bool] = FieldInfo(alias="localRunner", default=None) + """Use a local runner for the user""" diff --git a/src/gitpod/types/project_environment_class_param.py b/src/gitpod/types/project_environment_class_param.py new file mode 100644 index 0000000..c6e2918 --- /dev/null +++ b/src/gitpod/types/project_environment_class_param.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__ = ["ProjectEnvironmentClassParam"] + + +class ProjectEnvironmentClassParam(TypedDict, total=False): + environment_class_id: Annotated[str, PropertyInfo(alias="environmentClassId")] + """Use a fixed environment class on a given Runner. + + This cannot be a local runner's environment class. + """ + + local_runner: Annotated[bool, PropertyInfo(alias="localRunner")] + """Use a local runner for the user""" diff --git a/src/gitpod/types/project_list_params.py b/src/gitpod/types/project_list_params.py new file mode 100644 index 0000000..4709a7b --- /dev/null +++ b/src/gitpod/types/project_list_params.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["ProjectListParams", "Filter", "Pagination"] + + +class ProjectListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + """pagination contains the pagination options for listing organizations""" + + +class Filter(TypedDict, total=False): + project_ids: Annotated[List[str], PropertyInfo(alias="projectIds")] + """project_ids filters the response to only projects with these IDs""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/project_metadata.py b/src/gitpod/types/project_metadata.py new file mode 100644 index 0000000..5a39bda --- /dev/null +++ b/src/gitpod/types/project_metadata.py @@ -0,0 +1,206 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.subject import Subject + +__all__ = ["ProjectMetadata"] + + +class ProjectMetadata(BaseModel): + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + creator: Optional[Subject] = None + """creator is the identity of the project creator""" + + name: Optional[str] = None + """name is the human readable name of the project""" + + organization_id: Optional[str] = FieldInfo(alias="organizationId", default=None) + """organization_id is the ID of the organization that contains the environment""" + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ diff --git a/src/gitpod/types/project_retrieve_params.py b/src/gitpod/types/project_retrieve_params.py new file mode 100644 index 0000000..0160fa6 --- /dev/null +++ b/src/gitpod/types/project_retrieve_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["ProjectRetrieveParams"] + + +class ProjectRetrieveParams(TypedDict, total=False): + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """project_id specifies the project identifier""" diff --git a/src/gitpod/types/project_retrieve_response.py b/src/gitpod/types/project_retrieve_response.py new file mode 100644 index 0000000..066a721 --- /dev/null +++ b/src/gitpod/types/project_retrieve_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .project import Project +from .._models import BaseModel + +__all__ = ["ProjectRetrieveResponse"] + + +class ProjectRetrieveResponse(BaseModel): + project: Optional[Project] = None diff --git a/src/gitpod/types/project_update_params.py b/src/gitpod/types/project_update_params.py new file mode 100644 index 0000000..214d3fa --- /dev/null +++ b/src/gitpod/types/project_update_params.py @@ -0,0 +1,50 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo +from .environment_initializer_param import EnvironmentInitializerParam +from .project_environment_class_param import ProjectEnvironmentClassParam + +__all__ = ["ProjectUpdateParams"] + + +class ProjectUpdateParams(TypedDict, total=False): + automations_file_path: Annotated[Optional[str], PropertyInfo(alias="automationsFilePath")] + """ + automations_file_path is the path to the automations file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + devcontainer_file_path: Annotated[Optional[str], PropertyInfo(alias="devcontainerFilePath")] + """ + devcontainer_file_path is the path to the devcontainer file relative to the repo + root path must not be absolute (start with a /): + + ``` + this.matches('^$|^[^/].*') + ``` + """ + + environment_class: Annotated[Optional[ProjectEnvironmentClassParam], PropertyInfo(alias="environmentClass")] + + initializer: Optional[EnvironmentInitializerParam] + """initializer is the content initializer""" + + name: Optional[str] + + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """project_id specifies the project identifier""" + + technical_description: Annotated[Optional[str], PropertyInfo(alias="technicalDescription")] + """ + technical_description is a detailed technical description of the project This + field is not returned by default in GetProject or ListProjects responses 8KB max + """ diff --git a/src/gitpod/types/project_update_response.py b/src/gitpod/types/project_update_response.py new file mode 100644 index 0000000..b426723 --- /dev/null +++ b/src/gitpod/types/project_update_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .project import Project +from .._models import BaseModel + +__all__ = ["ProjectUpdateResponse"] + + +class ProjectUpdateResponse(BaseModel): + project: Optional[Project] = None diff --git a/src/gitpod/types/projects/__init__.py b/src/gitpod/types/projects/__init__.py new file mode 100644 index 0000000..f6f8d0b --- /dev/null +++ b/src/gitpod/types/projects/__init__.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .project_role import ProjectRole as ProjectRole +from .project_policy import ProjectPolicy as ProjectPolicy +from .policy_list_params import PolicyListParams as PolicyListParams +from .policy_create_params import PolicyCreateParams as PolicyCreateParams +from .policy_delete_params import PolicyDeleteParams as PolicyDeleteParams +from .policy_update_params import PolicyUpdateParams as PolicyUpdateParams +from .policy_create_response import PolicyCreateResponse as PolicyCreateResponse +from .policy_update_response import PolicyUpdateResponse as PolicyUpdateResponse diff --git a/src/gitpod/types/projects/policy_create_params.py b/src/gitpod/types/projects/policy_create_params.py new file mode 100644 index 0000000..1b72ad6 --- /dev/null +++ b/src/gitpod/types/projects/policy_create_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 +from .project_role import ProjectRole + +__all__ = ["PolicyCreateParams"] + + +class PolicyCreateParams(TypedDict, total=False): + group_id: Annotated[str, PropertyInfo(alias="groupId")] + """group_id specifies the group_id identifier""" + + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """project_id specifies the project identifier""" + + role: ProjectRole diff --git a/src/gitpod/types/projects/policy_create_response.py b/src/gitpod/types/projects/policy_create_response.py new file mode 100644 index 0000000..0d79a48 --- /dev/null +++ b/src/gitpod/types/projects/policy_create_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .project_policy import ProjectPolicy + +__all__ = ["PolicyCreateResponse"] + + +class PolicyCreateResponse(BaseModel): + policy: Optional[ProjectPolicy] = None diff --git a/src/gitpod/types/projects/policy_delete_params.py b/src/gitpod/types/projects/policy_delete_params.py new file mode 100644 index 0000000..bd51f1a --- /dev/null +++ b/src/gitpod/types/projects/policy_delete_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 Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["PolicyDeleteParams"] + + +class PolicyDeleteParams(TypedDict, total=False): + group_id: Annotated[str, PropertyInfo(alias="groupId")] + """group_id specifies the group_id identifier""" + + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """project_id specifies the project identifier""" diff --git a/src/gitpod/types/projects/policy_list_params.py b/src/gitpod/types/projects/policy_list_params.py new file mode 100644 index 0000000..9f86088 --- /dev/null +++ b/src/gitpod/types/projects/policy_list_params.py @@ -0,0 +1,35 @@ +# 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__ = ["PolicyListParams", "Pagination"] + + +class PolicyListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + pagination: Pagination + """pagination contains the pagination options for listing project policies""" + + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """project_id specifies the project identifier""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/projects/policy_update_params.py b/src/gitpod/types/projects/policy_update_params.py new file mode 100644 index 0000000..c53cb50 --- /dev/null +++ b/src/gitpod/types/projects/policy_update_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 +from .project_role import ProjectRole + +__all__ = ["PolicyUpdateParams"] + + +class PolicyUpdateParams(TypedDict, total=False): + group_id: Annotated[str, PropertyInfo(alias="groupId")] + """group_id specifies the group_id identifier""" + + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """project_id specifies the project identifier""" + + role: ProjectRole diff --git a/src/gitpod/types/projects/policy_update_response.py b/src/gitpod/types/projects/policy_update_response.py new file mode 100644 index 0000000..96b4cce --- /dev/null +++ b/src/gitpod/types/projects/policy_update_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .project_policy import ProjectPolicy + +__all__ = ["PolicyUpdateResponse"] + + +class PolicyUpdateResponse(BaseModel): + policy: Optional[ProjectPolicy] = None diff --git a/src/gitpod/types/projects/project_policy.py b/src/gitpod/types/projects/project_policy.py new file mode 100644 index 0000000..dfeb4e9 --- /dev/null +++ b/src/gitpod/types/projects/project_policy.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .project_role import ProjectRole + +__all__ = ["ProjectPolicy"] + + +class ProjectPolicy(BaseModel): + group_id: Optional[str] = FieldInfo(alias="groupId", default=None) + + role: Optional[ProjectRole] = None + """role is the role assigned to the group""" diff --git a/src/gitpod/types/projects/project_role.py b/src/gitpod/types/projects/project_role.py new file mode 100644 index 0000000..e488d52 --- /dev/null +++ b/src/gitpod/types/projects/project_role.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ProjectRole"] + +ProjectRole: TypeAlias = Literal[ + "PROJECT_ROLE_UNSPECIFIED", "PROJECT_ROLE_ADMIN", "PROJECT_ROLE_USER", "PROJECT_ROLE_EDITOR" +] diff --git a/src/gitpod/types/resource_operation.py b/src/gitpod/types/resource_operation.py new file mode 100644 index 0000000..3527c79 --- /dev/null +++ b/src/gitpod/types/resource_operation.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ResourceOperation"] + +ResourceOperation: TypeAlias = Literal[ + "RESOURCE_OPERATION_UNSPECIFIED", + "RESOURCE_OPERATION_CREATE", + "RESOURCE_OPERATION_UPDATE", + "RESOURCE_OPERATION_DELETE", + "RESOURCE_OPERATION_UPDATE_STATUS", +] diff --git a/src/gitpod/types/resource_type.py b/src/gitpod/types/resource_type.py new file mode 100644 index 0000000..c273d47 --- /dev/null +++ b/src/gitpod/types/resource_type.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ResourceType"] + +ResourceType: TypeAlias = Literal[ + "RESOURCE_TYPE_UNSPECIFIED", + "RESOURCE_TYPE_ENVIRONMENT", + "RESOURCE_TYPE_RUNNER", + "RESOURCE_TYPE_PROJECT", + "RESOURCE_TYPE_TASK", + "RESOURCE_TYPE_TASK_EXECUTION", + "RESOURCE_TYPE_SERVICE", + "RESOURCE_TYPE_ORGANIZATION", + "RESOURCE_TYPE_USER", + "RESOURCE_TYPE_ENVIRONMENT_CLASS", + "RESOURCE_TYPE_RUNNER_SCM_INTEGRATION", + "RESOURCE_TYPE_HOST_AUTHENTICATION_TOKEN", + "RESOURCE_TYPE_GROUP", + "RESOURCE_TYPE_PERSONAL_ACCESS_TOKEN", + "RESOURCE_TYPE_USER_PREFERENCE", + "RESOURCE_TYPE_SERVICE_ACCOUNT", + "RESOURCE_TYPE_SECRET", + "RESOURCE_TYPE_SSO_CONFIG", + "RESOURCE_TYPE_DOMAIN_VERIFICATION", + "RESOURCE_TYPE_AGENT_EXECUTION", + "RESOURCE_TYPE_RUNNER_LLM_INTEGRATION", + "RESOURCE_TYPE_AGENT", + "RESOURCE_TYPE_ENVIRONMENT_SESSION", + "RESOURCE_TYPE_USER_SECRET", + "RESOURCE_TYPE_ORGANIZATION_POLICY", +] diff --git a/src/gitpod/types/runner.py b/src/gitpod/types/runner.py new file mode 100644 index 0000000..ec169a3 --- /dev/null +++ b/src/gitpod/types/runner.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .runner_kind import RunnerKind +from .runner_spec import RunnerSpec +from .runner_status import RunnerStatus +from .shared.subject import Subject +from .runner_provider import RunnerProvider + +__all__ = ["Runner"] + + +class Runner(BaseModel): + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """Time when the Runner was created.""" + + creator: Optional[Subject] = None + """creator is the identity of the creator of the environment""" + + kind: Optional[RunnerKind] = None + """The runner's kind""" + + name: Optional[str] = None + """The runner's name which is shown to users""" + + provider: Optional[RunnerProvider] = None + """The runner's provider""" + + runner_id: Optional[str] = FieldInfo(alias="runnerId", default=None) + + spec: Optional[RunnerSpec] = None + """The runner's specification""" + + status: Optional[RunnerStatus] = None + """The runner's status""" + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + """Time when the Runner was last udpated.""" diff --git a/src/gitpod/types/runner_capability.py b/src/gitpod/types/runner_capability.py new file mode 100644 index 0000000..0a66872 --- /dev/null +++ b/src/gitpod/types/runner_capability.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["RunnerCapability"] + +RunnerCapability: TypeAlias = Literal[ + "RUNNER_CAPABILITY_UNSPECIFIED", + "RUNNER_CAPABILITY_FETCH_LOCAL_SCM_INTEGRATIONS", + "RUNNER_CAPABILITY_SECRET_CONTAINER_REGISTRY", + "RUNNER_CAPABILITY_AGENT_EXECUTION", + "RUNNER_CAPABILITY_ALLOW_ENV_TOKEN_POPULATION", + "RUNNER_CAPABILITY_DEFAULT_DEV_CONTAINER_IMAGE", +] diff --git a/src/gitpod/types/runner_check_authentication_for_host_params.py b/src/gitpod/types/runner_check_authentication_for_host_params.py new file mode 100644 index 0000000..c3a5db4 --- /dev/null +++ b/src/gitpod/types/runner_check_authentication_for_host_params.py @@ -0,0 +1,15 @@ +# 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__ = ["RunnerCheckAuthenticationForHostParams"] + + +class RunnerCheckAuthenticationForHostParams(TypedDict, total=False): + host: str + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] diff --git a/src/gitpod/types/runner_check_authentication_for_host_response.py b/src/gitpod/types/runner_check_authentication_for_host_response.py new file mode 100644 index 0000000..273d871 --- /dev/null +++ b/src/gitpod/types/runner_check_authentication_for_host_response.py @@ -0,0 +1,60 @@ +# 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__ = ["RunnerCheckAuthenticationForHostResponse", "SupportsOauth2", "SupportsPat"] + + +class SupportsOauth2(BaseModel): + auth_url: Optional[str] = FieldInfo(alias="authUrl", default=None) + """auth_url is the URL where users can authenticate""" + + docs_url: Optional[str] = FieldInfo(alias="docsUrl", default=None) + """docs_url is the URL to the documentation explaining this authentication method""" + + +class SupportsPat(BaseModel): + create_url: Optional[str] = FieldInfo(alias="createUrl", default=None) + """create_url is the URL where users can create a new Personal Access Token""" + + docs_url: Optional[str] = FieldInfo(alias="docsUrl", default=None) + """docs_url is the URL to the documentation explaining PAT usage for this host""" + + example: Optional[str] = None + """example is an example of a Personal Access Token""" + + required_scopes: Optional[List[str]] = FieldInfo(alias="requiredScopes", default=None) + """ + required_scopes is the list of permissions required for the Personal Access + Token + """ + + +class RunnerCheckAuthenticationForHostResponse(BaseModel): + authenticated: Optional[bool] = None + + authentication_url: Optional[str] = FieldInfo(alias="authenticationUrl", default=None) + + pat_supported: Optional[bool] = FieldInfo(alias="patSupported", default=None) + + scm_id: Optional[str] = FieldInfo(alias="scmId", default=None) + """scm_id is the unique identifier of the SCM provider""" + + scm_name: Optional[str] = FieldInfo(alias="scmName", default=None) + """ + scm_name is the human-readable name of the SCM provider (e.g., "GitHub", + "GitLab") + """ + + supports_oauth2: Optional[SupportsOauth2] = FieldInfo(alias="supportsOauth2", default=None) + """supports_oauth2 indicates that the host supports OAuth2 authentication""" + + supports_pat: Optional[SupportsPat] = FieldInfo(alias="supportsPat", default=None) + """ + supports_pat indicates that the host supports Personal Access Token + authentication + """ diff --git a/src/gitpod/types/runner_configuration.py b/src/gitpod/types/runner_configuration.py new file mode 100644 index 0000000..4f91d55 --- /dev/null +++ b/src/gitpod/types/runner_configuration.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .log_level import LogLevel +from .metrics_configuration import MetricsConfiguration +from .runner_release_channel import RunnerReleaseChannel + +__all__ = ["RunnerConfiguration"] + + +class RunnerConfiguration(BaseModel): + auto_update: Optional[bool] = FieldInfo(alias="autoUpdate", default=None) + """auto_update indicates whether the runner should automatically update itself.""" + + devcontainer_image_cache_enabled: Optional[bool] = FieldInfo(alias="devcontainerImageCacheEnabled", default=None) + """ + devcontainer_image_cache_enabled controls whether the devcontainer build cache + is enabled for this runner. Only takes effect on supported runners, currently + only AWS EC2 runners. + """ + + log_level: Optional[LogLevel] = FieldInfo(alias="logLevel", default=None) + """log_level is the log level for the runner""" + + metrics: Optional[MetricsConfiguration] = None + """metrics contains configuration for the runner's metrics collection""" + + region: Optional[str] = None + """ + Region to deploy the runner in, if applicable. This is mainly used for remote + runners, and is only a hint. The runner may be deployed in a different region. + See the runner's status for the actual region. + """ + + release_channel: Optional[RunnerReleaseChannel] = FieldInfo(alias="releaseChannel", default=None) + """The release channel the runner is on""" diff --git a/src/gitpod/types/runner_configuration_param.py b/src/gitpod/types/runner_configuration_param.py new file mode 100644 index 0000000..7ba49ee --- /dev/null +++ b/src/gitpod/types/runner_configuration_param.py @@ -0,0 +1,40 @@ +# 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 +from .log_level import LogLevel +from .runner_release_channel import RunnerReleaseChannel +from .metrics_configuration_param import MetricsConfigurationParam + +__all__ = ["RunnerConfigurationParam"] + + +class RunnerConfigurationParam(TypedDict, total=False): + auto_update: Annotated[bool, PropertyInfo(alias="autoUpdate")] + """auto_update indicates whether the runner should automatically update itself.""" + + devcontainer_image_cache_enabled: Annotated[bool, PropertyInfo(alias="devcontainerImageCacheEnabled")] + """ + devcontainer_image_cache_enabled controls whether the devcontainer build cache + is enabled for this runner. Only takes effect on supported runners, currently + only AWS EC2 runners. + """ + + log_level: Annotated[LogLevel, PropertyInfo(alias="logLevel")] + """log_level is the log level for the runner""" + + metrics: MetricsConfigurationParam + """metrics contains configuration for the runner's metrics collection""" + + region: str + """ + Region to deploy the runner in, if applicable. This is mainly used for remote + runners, and is only a hint. The runner may be deployed in a different region. + See the runner's status for the actual region. + """ + + release_channel: Annotated[RunnerReleaseChannel, PropertyInfo(alias="releaseChannel")] + """The release channel the runner is on""" diff --git a/src/gitpod/types/runner_create_params.py b/src/gitpod/types/runner_create_params.py new file mode 100644 index 0000000..6834fa3 --- /dev/null +++ b/src/gitpod/types/runner_create_params.py @@ -0,0 +1,39 @@ +# 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 +from .runner_kind import RunnerKind +from .runner_provider import RunnerProvider +from .runner_spec_param import RunnerSpecParam + +__all__ = ["RunnerCreateParams"] + + +class RunnerCreateParams(TypedDict, total=False): + kind: RunnerKind + """The runner's kind This field is optional and here for backwards-compatibility. + + Use the provider field instead. If provider is set, the runner's kind will be + deduced from the provider. Only one of kind and provider must be set. + """ + + name: str + """The runner name for humans""" + + provider: RunnerProvider + """ + The specific implementation type of the runner This field is optional for + backwards compatibility but will be required in the future. When specified, kind + must not be specified (will be deduced from provider) + """ + + runner_manager_id: Annotated[str, PropertyInfo(alias="runnerManagerId")] + """ + The runner manager id specifies the runner manager for the managed runner. This + field is mandatory for managed runners, otheriwse should not be set. + """ + + spec: RunnerSpecParam diff --git a/src/gitpod/types/runner_create_response.py b/src/gitpod/types/runner_create_response.py new file mode 100644 index 0000000..2f6821f --- /dev/null +++ b/src/gitpod/types/runner_create_response.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .runner import Runner +from .._models import BaseModel + +__all__ = ["RunnerCreateResponse"] + + +class RunnerCreateResponse(BaseModel): + runner: Runner + + access_token: Optional[str] = FieldInfo(alias="accessToken", default=None) + """deprecated, will be removed. Use exchange_token instead.""" + + exchange_token: Optional[str] = FieldInfo(alias="exchangeToken", default=None) + """ + exchange_token is a one-time use token that should be exchanged by the runner + for an access token, using the IdentityService.ExchangeToken rpc. The token + expires after 24 hours. + """ diff --git a/src/gitpod/types/runner_create_runner_token_params.py b/src/gitpod/types/runner_create_runner_token_params.py new file mode 100644 index 0000000..8bf7b70 --- /dev/null +++ b/src/gitpod/types/runner_create_runner_token_params.py @@ -0,0 +1,13 @@ +# 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__ = ["RunnerCreateRunnerTokenParams"] + + +class RunnerCreateRunnerTokenParams(TypedDict, total=False): + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] diff --git a/src/gitpod/types/runner_create_runner_token_response.py b/src/gitpod/types/runner_create_runner_token_response.py new file mode 100644 index 0000000..0f793a3 --- /dev/null +++ b/src/gitpod/types/runner_create_runner_token_response.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["RunnerCreateRunnerTokenResponse"] + + +class RunnerCreateRunnerTokenResponse(BaseModel): + access_token: Optional[str] = FieldInfo(alias="accessToken", default=None) + """deprecated, will be removed. Use exchange_token instead.""" + + exchange_token: Optional[str] = FieldInfo(alias="exchangeToken", default=None) + """ + exchange_token is a one-time use token that should be exchanged by the runner + for an access token, using the IdentityService.ExchangeToken rpc. The token + expires after 24 hours. + """ diff --git a/src/gitpod/types/runner_delete_params.py b/src/gitpod/types/runner_delete_params.py new file mode 100644 index 0000000..a532268 --- /dev/null +++ b/src/gitpod/types/runner_delete_params.py @@ -0,0 +1,21 @@ +# 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__ = ["RunnerDeleteParams"] + + +class RunnerDeleteParams(TypedDict, total=False): + force: bool + """ + force indicates whether the runner should be deleted forcefully. When force + deleting a Runner, all Environments on the runner are also force deleted and + regular Runner lifecycle is not respected. Force deleting can result in data + loss. + """ + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] diff --git a/src/gitpod/types/runner_kind.py b/src/gitpod/types/runner_kind.py new file mode 100644 index 0000000..2302dbe --- /dev/null +++ b/src/gitpod/types/runner_kind.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["RunnerKind"] + +RunnerKind: TypeAlias = Literal[ + "RUNNER_KIND_UNSPECIFIED", "RUNNER_KIND_LOCAL", "RUNNER_KIND_REMOTE", "RUNNER_KIND_LOCAL_CONFIGURATION" +] diff --git a/src/gitpod/types/runner_list_params.py b/src/gitpod/types/runner_list_params.py new file mode 100644 index 0000000..7d2a986 --- /dev/null +++ b/src/gitpod/types/runner_list_params.py @@ -0,0 +1,48 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo +from .runner_kind import RunnerKind +from .runner_provider import RunnerProvider + +__all__ = ["RunnerListParams", "Filter", "Pagination"] + + +class RunnerListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + """pagination contains the pagination options for listing runners""" + + +class Filter(TypedDict, total=False): + creator_ids: Annotated[List[str], PropertyInfo(alias="creatorIds")] + """creator_ids filters the response to only runner created by specified users""" + + kinds: List[RunnerKind] + """kinds filters the response to only runners of the specified kinds""" + + providers: List[RunnerProvider] + """providers filters the response to only runners of the specified providers""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/runner_parse_context_url_params.py b/src/gitpod/types/runner_parse_context_url_params.py new file mode 100644 index 0000000..986d37b --- /dev/null +++ b/src/gitpod/types/runner_parse_context_url_params.py @@ -0,0 +1,15 @@ +# 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__ = ["RunnerParseContextURLParams"] + + +class RunnerParseContextURLParams(TypedDict, total=False): + context_url: Annotated[str, PropertyInfo(alias="contextUrl")] + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] diff --git a/src/gitpod/types/runner_parse_context_url_response.py b/src/gitpod/types/runner_parse_context_url_response.py new file mode 100644 index 0000000..e34f770 --- /dev/null +++ b/src/gitpod/types/runner_parse_context_url_response.py @@ -0,0 +1,34 @@ +# 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__ = ["RunnerParseContextURLResponse", "Git"] + + +class Git(BaseModel): + branch: Optional[str] = None + + clone_url: Optional[str] = FieldInfo(alias="cloneUrl", default=None) + + commit: Optional[str] = None + + host: Optional[str] = None + + owner: Optional[str] = None + + repo: Optional[str] = None + + upstream_remote_url: Optional[str] = FieldInfo(alias="upstreamRemoteUrl", default=None) + + +class RunnerParseContextURLResponse(BaseModel): + git: Optional[Git] = None + + original_context_url: Optional[str] = FieldInfo(alias="originalContextUrl", default=None) + + project_ids: Optional[List[str]] = FieldInfo(alias="projectIds", default=None) + """project_ids is a list of projects to which the context URL belongs to.""" diff --git a/src/gitpod/types/runner_phase.py b/src/gitpod/types/runner_phase.py new file mode 100644 index 0000000..b7cd3e9 --- /dev/null +++ b/src/gitpod/types/runner_phase.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["RunnerPhase"] + +RunnerPhase: TypeAlias = Literal[ + "RUNNER_PHASE_UNSPECIFIED", + "RUNNER_PHASE_CREATED", + "RUNNER_PHASE_INACTIVE", + "RUNNER_PHASE_ACTIVE", + "RUNNER_PHASE_DELETING", + "RUNNER_PHASE_DELETED", + "RUNNER_PHASE_DEGRADED", +] diff --git a/src/gitpod/types/runner_provider.py b/src/gitpod/types/runner_provider.py new file mode 100644 index 0000000..8f8efef --- /dev/null +++ b/src/gitpod/types/runner_provider.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["RunnerProvider"] + +RunnerProvider: TypeAlias = Literal[ + "RUNNER_PROVIDER_UNSPECIFIED", + "RUNNER_PROVIDER_AWS_EC2", + "RUNNER_PROVIDER_LINUX_HOST", + "RUNNER_PROVIDER_DESKTOP_MAC", + "RUNNER_PROVIDER_MANAGED", +] diff --git a/src/gitpod/types/runner_release_channel.py b/src/gitpod/types/runner_release_channel.py new file mode 100644 index 0000000..c85e07a --- /dev/null +++ b/src/gitpod/types/runner_release_channel.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["RunnerReleaseChannel"] + +RunnerReleaseChannel: TypeAlias = Literal[ + "RUNNER_RELEASE_CHANNEL_UNSPECIFIED", "RUNNER_RELEASE_CHANNEL_STABLE", "RUNNER_RELEASE_CHANNEL_LATEST" +] diff --git a/src/gitpod/types/runner_retrieve_params.py b/src/gitpod/types/runner_retrieve_params.py new file mode 100644 index 0000000..409766f --- /dev/null +++ b/src/gitpod/types/runner_retrieve_params.py @@ -0,0 +1,13 @@ +# 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__ = ["RunnerRetrieveParams"] + + +class RunnerRetrieveParams(TypedDict, total=False): + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] diff --git a/src/gitpod/types/runner_retrieve_response.py b/src/gitpod/types/runner_retrieve_response.py new file mode 100644 index 0000000..b4ec6d8 --- /dev/null +++ b/src/gitpod/types/runner_retrieve_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .runner import Runner +from .._models import BaseModel + +__all__ = ["RunnerRetrieveResponse"] + + +class RunnerRetrieveResponse(BaseModel): + runner: Runner diff --git a/src/gitpod/types/runner_spec.py b/src/gitpod/types/runner_spec.py new file mode 100644 index 0000000..9fb4811 --- /dev/null +++ b/src/gitpod/types/runner_spec.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .runner_phase import RunnerPhase +from .runner_configuration import RunnerConfiguration + +__all__ = ["RunnerSpec"] + + +class RunnerSpec(BaseModel): + configuration: Optional[RunnerConfiguration] = None + """The runner's configuration""" + + desired_phase: Optional[RunnerPhase] = FieldInfo(alias="desiredPhase", default=None) + """RunnerPhase represents the phase a runner is in""" diff --git a/src/gitpod/types/runner_spec_param.py b/src/gitpod/types/runner_spec_param.py new file mode 100644 index 0000000..c356eb3 --- /dev/null +++ b/src/gitpod/types/runner_spec_param.py @@ -0,0 +1,19 @@ +# 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 +from .runner_phase import RunnerPhase +from .runner_configuration_param import RunnerConfigurationParam + +__all__ = ["RunnerSpecParam"] + + +class RunnerSpecParam(TypedDict, total=False): + configuration: RunnerConfigurationParam + """The runner's configuration""" + + desired_phase: Annotated[RunnerPhase, PropertyInfo(alias="desiredPhase")] + """RunnerPhase represents the phase a runner is in""" diff --git a/src/gitpod/types/runner_status.py b/src/gitpod/types/runner_status.py new file mode 100644 index 0000000..a302c70 --- /dev/null +++ b/src/gitpod/types/runner_status.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .gateway_info import GatewayInfo +from .runner_phase import RunnerPhase +from .runner_capability import RunnerCapability +from .shared.field_value import FieldValue + +__all__ = ["RunnerStatus"] + + +class RunnerStatus(BaseModel): + additional_info: Optional[List[FieldValue]] = FieldInfo(alias="additionalInfo", default=None) + """additional_info contains additional information about the runner, e.g. + + a CloudFormation stack URL. + """ + + capabilities: Optional[List[RunnerCapability]] = None + """capabilities is a list of capabilities the runner supports.""" + + gateway_info: Optional[GatewayInfo] = FieldInfo(alias="gatewayInfo", default=None) + """gateway_info is information about the gateway to which the runner is connected.""" + + log_url: Optional[str] = FieldInfo(alias="logUrl", default=None) + + message: Optional[str] = None + """ + The runner's reported message which is shown to users. This message adds more + context to the runner's phase. + """ + + phase: Optional[RunnerPhase] = None + """The runner's reported phase""" + + region: Optional[str] = None + """region is the region the runner is running in, if applicable.""" + + system_details: Optional[str] = FieldInfo(alias="systemDetails", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + """Time when the status was last updated.""" + + version: Optional[str] = None diff --git a/src/gitpod/types/runner_update_params.py b/src/gitpod/types/runner_update_params.py new file mode 100644 index 0000000..4bef0fe --- /dev/null +++ b/src/gitpod/types/runner_update_params.py @@ -0,0 +1,77 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo +from .log_level import LogLevel +from .runner_phase import RunnerPhase +from .runner_release_channel import RunnerReleaseChannel + +__all__ = ["RunnerUpdateParams", "Spec", "SpecConfiguration", "SpecConfigurationMetrics"] + + +class RunnerUpdateParams(TypedDict, total=False): + name: Optional[str] + """The runner's name which is shown to users""" + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] + """runner_id specifies which runner to be updated. + + +required + """ + + spec: Optional[Spec] + + +class SpecConfigurationMetrics(TypedDict, total=False): + enabled: Optional[bool] + """enabled indicates whether the runner should collect metrics""" + + password: Optional[str] + """password is the password to use for the metrics collector""" + + url: Optional[str] + """url is the URL of the metrics collector""" + + username: Optional[str] + """username is the username to use for the metrics collector""" + + +class SpecConfiguration(TypedDict, total=False): + auto_update: Annotated[Optional[bool], PropertyInfo(alias="autoUpdate")] + """auto_update indicates whether the runner should automatically update itself.""" + + devcontainer_image_cache_enabled: Annotated[Optional[bool], PropertyInfo(alias="devcontainerImageCacheEnabled")] + """ + devcontainer_image_cache_enabled controls whether the shared devcontainer build + cache is enabled for this runner. + """ + + log_level: Annotated[Optional[LogLevel], PropertyInfo(alias="logLevel")] + """log_level is the log level for the runner""" + + metrics: Optional[SpecConfigurationMetrics] + """metrics contains configuration for the runner's metrics collection""" + + release_channel: Annotated[Optional[RunnerReleaseChannel], PropertyInfo(alias="releaseChannel")] + """The release channel the runner is on""" + + +class Spec(TypedDict, total=False): + configuration: Optional[SpecConfiguration] + + desired_phase: Annotated[Optional[RunnerPhase], PropertyInfo(alias="desiredPhase")] + """ + desired_phase can currently only be updated on local-configuration runners, to + toggle whether local runners are allowed for running environments in the + organization. Set to: + + - ACTIVE to enable local runners. + - INACTIVE to disable all local runners. Existing local runners and their + environments will stop, and cannot be started again until the desired_phase is + set to ACTIVE. Use this carefully, as it will affect all users in the + organization who use local runners. + """ diff --git a/src/gitpod/types/runners/__init__.py b/src/gitpod/types/runners/__init__.py new file mode 100644 index 0000000..4d19ee2 --- /dev/null +++ b/src/gitpod/types/runners/__init__.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .runner_role import RunnerRole as RunnerRole +from .runner_policy import RunnerPolicy as RunnerPolicy +from .policy_list_params import PolicyListParams as PolicyListParams +from .policy_create_params import PolicyCreateParams as PolicyCreateParams +from .policy_delete_params import PolicyDeleteParams as PolicyDeleteParams +from .policy_update_params import PolicyUpdateParams as PolicyUpdateParams +from .field_validation_error import FieldValidationError as FieldValidationError +from .policy_create_response import PolicyCreateResponse as PolicyCreateResponse +from .policy_update_response import PolicyUpdateResponse as PolicyUpdateResponse +from .configuration_validate_params import ConfigurationValidateParams as ConfigurationValidateParams +from .configuration_validate_response import ConfigurationValidateResponse as ConfigurationValidateResponse +from .scm_integration_validation_result import ScmIntegrationValidationResult as ScmIntegrationValidationResult +from .environment_class_validation_result import EnvironmentClassValidationResult as EnvironmentClassValidationResult diff --git a/src/gitpod/types/runners/configuration_validate_params.py b/src/gitpod/types/runners/configuration_validate_params.py new file mode 100644 index 0000000..8afdbe5 --- /dev/null +++ b/src/gitpod/types/runners/configuration_validate_params.py @@ -0,0 +1,68 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Annotated, TypedDict + +from ..._types import Base64FileInput +from ..._utils import PropertyInfo +from ..._models import set_pydantic_config +from ..shared_params.environment_class import EnvironmentClass + +__all__ = ["ConfigurationValidateParams", "ScmIntegration"] + + +class ConfigurationValidateParams(TypedDict, total=False): + environment_class: Annotated[EnvironmentClass, PropertyInfo(alias="environmentClass")] + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] + + scm_integration: Annotated[ScmIntegration, PropertyInfo(alias="scmIntegration")] + + +class ScmIntegration(TypedDict, total=False): + id: str + """id is the unique identifier of the SCM integration""" + + host: str + + issuer_url: Annotated[Optional[str], PropertyInfo(alias="issuerUrl")] + """ + issuer_url can be set to override the authentication provider URL, if it doesn't + match the SCM host. + """ + + oauth_client_id: Annotated[Optional[str], PropertyInfo(alias="oauthClientId")] + """ + oauth_client_id is the OAuth app's client ID, if OAuth is configured. If + configured, oauth_client_secret must also be set. + """ + + oauth_encrypted_client_secret: Annotated[ + Union[str, Base64FileInput], PropertyInfo(alias="oauthEncryptedClientSecret", format="base64") + ] + """ + oauth_encrypted_client_secret is the OAuth app's client secret encrypted with + the runner's public key, if OAuth is configured. This can be used to e.g. + validate an already encrypted client secret of an existing SCM integration. + """ + + oauth_plaintext_client_secret: Annotated[str, PropertyInfo(alias="oauthPlaintextClientSecret")] + """ + oauth_plaintext_client_secret is the OAuth app's client secret in clear text, if + OAuth is configured. This can be set to validate any new client secret before it + is encrypted and stored. This value will not be stored and get encrypted with + the runner's public key before passing it to the runner. + """ + + pat: bool + + scm_id: Annotated[str, PropertyInfo(alias="scmId")] + """ + scm_id references the scm_id in the runner's configuration schema that this + integration is for + """ + + +set_pydantic_config(ScmIntegration, {"arbitrary_types_allowed": True}) diff --git a/src/gitpod/types/runners/configuration_validate_response.py b/src/gitpod/types/runners/configuration_validate_response.py new file mode 100644 index 0000000..3009132 --- /dev/null +++ b/src/gitpod/types/runners/configuration_validate_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .scm_integration_validation_result import ScmIntegrationValidationResult +from .environment_class_validation_result import EnvironmentClassValidationResult + +__all__ = ["ConfigurationValidateResponse"] + + +class ConfigurationValidateResponse(BaseModel): + environment_class: Optional[EnvironmentClassValidationResult] = FieldInfo(alias="environmentClass", default=None) + + scm_integration: Optional[ScmIntegrationValidationResult] = FieldInfo(alias="scmIntegration", default=None) diff --git a/src/gitpod/types/runners/configurations/__init__.py b/src/gitpod/types/runners/configurations/__init__.py new file mode 100644 index 0000000..5a36d94 --- /dev/null +++ b/src/gitpod/types/runners/configurations/__init__.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .scm_integration import ScmIntegration as ScmIntegration +from .schema_retrieve_params import SchemaRetrieveParams as SchemaRetrieveParams +from .schema_retrieve_response import SchemaRetrieveResponse as SchemaRetrieveResponse +from .host_authentication_token import HostAuthenticationToken as HostAuthenticationToken +from .runner_configuration_schema import RunnerConfigurationSchema as RunnerConfigurationSchema +from .scm_integration_list_params import ScmIntegrationListParams as ScmIntegrationListParams +from .scm_integration_oauth_config import ScmIntegrationOAuthConfig as ScmIntegrationOAuthConfig +from .environment_class_list_params import EnvironmentClassListParams as EnvironmentClassListParams +from .scm_integration_create_params import ScmIntegrationCreateParams as ScmIntegrationCreateParams +from .scm_integration_delete_params import ScmIntegrationDeleteParams as ScmIntegrationDeleteParams +from .scm_integration_update_params import ScmIntegrationUpdateParams as ScmIntegrationUpdateParams +from .environment_class_create_params import EnvironmentClassCreateParams as EnvironmentClassCreateParams +from .environment_class_update_params import EnvironmentClassUpdateParams as EnvironmentClassUpdateParams +from .scm_integration_create_response import ScmIntegrationCreateResponse as ScmIntegrationCreateResponse +from .scm_integration_retrieve_params import ScmIntegrationRetrieveParams as ScmIntegrationRetrieveParams +from .host_authentication_token_source import HostAuthenticationTokenSource as HostAuthenticationTokenSource +from .environment_class_create_response import EnvironmentClassCreateResponse as EnvironmentClassCreateResponse +from .environment_class_retrieve_params import EnvironmentClassRetrieveParams as EnvironmentClassRetrieveParams +from .scm_integration_retrieve_response import ScmIntegrationRetrieveResponse as ScmIntegrationRetrieveResponse +from .environment_class_retrieve_response import EnvironmentClassRetrieveResponse as EnvironmentClassRetrieveResponse +from .host_authentication_token_list_params import ( + HostAuthenticationTokenListParams as HostAuthenticationTokenListParams, +) +from .host_authentication_token_create_params import ( + HostAuthenticationTokenCreateParams as HostAuthenticationTokenCreateParams, +) +from .host_authentication_token_delete_params import ( + HostAuthenticationTokenDeleteParams as HostAuthenticationTokenDeleteParams, +) +from .host_authentication_token_update_params import ( + HostAuthenticationTokenUpdateParams as HostAuthenticationTokenUpdateParams, +) +from .host_authentication_token_create_response import ( + HostAuthenticationTokenCreateResponse as HostAuthenticationTokenCreateResponse, +) +from .host_authentication_token_retrieve_params import ( + HostAuthenticationTokenRetrieveParams as HostAuthenticationTokenRetrieveParams, +) +from .host_authentication_token_retrieve_response import ( + HostAuthenticationTokenRetrieveResponse as HostAuthenticationTokenRetrieveResponse, +) diff --git a/src/gitpod/types/runners/configurations/environment_class_create_params.py b/src/gitpod/types/runners/configurations/environment_class_create_params.py new file mode 100644 index 0000000..1f624b0 --- /dev/null +++ b/src/gitpod/types/runners/configurations/environment_class_create_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo +from ...shared_params.field_value import FieldValue + +__all__ = ["EnvironmentClassCreateParams"] + + +class EnvironmentClassCreateParams(TypedDict, total=False): + configuration: Iterable[FieldValue] + + description: str + + display_name: Annotated[str, PropertyInfo(alias="displayName")] + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] diff --git a/src/gitpod/types/runners/configurations/environment_class_create_response.py b/src/gitpod/types/runners/configurations/environment_class_create_response.py new file mode 100644 index 0000000..47198a0 --- /dev/null +++ b/src/gitpod/types/runners/configurations/environment_class_create_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["EnvironmentClassCreateResponse"] + + +class EnvironmentClassCreateResponse(BaseModel): + id: Optional[str] = None diff --git a/src/gitpod/types/runners/configurations/environment_class_list_params.py b/src/gitpod/types/runners/configurations/environment_class_list_params.py new file mode 100644 index 0000000..14cdf32 --- /dev/null +++ b/src/gitpod/types/runners/configurations/environment_class_list_params.py @@ -0,0 +1,68 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo +from ...runner_kind import RunnerKind +from ...runner_provider import RunnerProvider + +__all__ = ["EnvironmentClassListParams", "Filter", "Pagination"] + + +class EnvironmentClassListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + """pagination contains the pagination options for listing environment classes""" + + +class Filter(TypedDict, total=False): + can_create_environments: Annotated[Optional[bool], PropertyInfo(alias="canCreateEnvironments")] + """ + can_create_environments filters the response to only environment classes that + can be used to create new environments by the caller. Unlike enabled, which + indicates general availability, this ensures the caller only sees environment + classes they are allowed to use. + """ + + enabled: Optional[bool] + """ + enabled filters the response to only enabled or disabled environment classes. If + not set, all environment classes are returned. + """ + + runner_ids: Annotated[List[str], PropertyInfo(alias="runnerIds")] + """runner_ids filters the response to only EnvironmentClasses of these Runner IDs""" + + runner_kinds: Annotated[List[RunnerKind], PropertyInfo(alias="runnerKinds")] + """ + runner_kind filters the response to only environment classes from runners of + these kinds. + """ + + runner_providers: Annotated[List[RunnerProvider], PropertyInfo(alias="runnerProviders")] + """ + runner_providers filters the response to only environment classes from runners + of these providers. + """ + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/runners/configurations/environment_class_retrieve_params.py b/src/gitpod/types/runners/configurations/environment_class_retrieve_params.py new file mode 100644 index 0000000..51b92e1 --- /dev/null +++ b/src/gitpod/types/runners/configurations/environment_class_retrieve_params.py @@ -0,0 +1,13 @@ +# 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__ = ["EnvironmentClassRetrieveParams"] + + +class EnvironmentClassRetrieveParams(TypedDict, total=False): + environment_class_id: Annotated[str, PropertyInfo(alias="environmentClassId")] diff --git a/src/gitpod/types/runners/configurations/environment_class_retrieve_response.py b/src/gitpod/types/runners/configurations/environment_class_retrieve_response.py new file mode 100644 index 0000000..36ad250 --- /dev/null +++ b/src/gitpod/types/runners/configurations/environment_class_retrieve_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from ...shared.environment_class import EnvironmentClass + +__all__ = ["EnvironmentClassRetrieveResponse"] + + +class EnvironmentClassRetrieveResponse(BaseModel): + environment_class: Optional[EnvironmentClass] = FieldInfo(alias="environmentClass", default=None) diff --git a/src/gitpod/types/runners/configurations/environment_class_update_params.py b/src/gitpod/types/runners/configurations/environment_class_update_params.py new file mode 100644 index 0000000..e161361 --- /dev/null +++ b/src/gitpod/types/runners/configurations/environment_class_update_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 import Optional +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["EnvironmentClassUpdateParams"] + + +class EnvironmentClassUpdateParams(TypedDict, total=False): + description: Optional[str] + + display_name: Annotated[Optional[str], PropertyInfo(alias="displayName")] + + enabled: Optional[bool] + + environment_class_id: Annotated[str, PropertyInfo(alias="environmentClassId")] diff --git a/src/gitpod/types/runners/configurations/host_authentication_token.py b/src/gitpod/types/runners/configurations/host_authentication_token.py new file mode 100644 index 0000000..22e5760 --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from .host_authentication_token_source import HostAuthenticationTokenSource + +__all__ = ["HostAuthenticationToken"] + + +class HostAuthenticationToken(BaseModel): + id: str + + expires_at: Optional[datetime] = FieldInfo(alias="expiresAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + host: Optional[str] = None + + runner_id: Optional[str] = FieldInfo(alias="runnerId", default=None) + + source: Optional[HostAuthenticationTokenSource] = None + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) diff --git a/src/gitpod/types/runners/configurations/host_authentication_token_create_params.py b/src/gitpod/types/runners/configurations/host_authentication_token_create_params.py new file mode 100644 index 0000000..f0ba68e --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token_create_params.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo +from .host_authentication_token_source import HostAuthenticationTokenSource + +__all__ = ["HostAuthenticationTokenCreateParams"] + + +class HostAuthenticationTokenCreateParams(TypedDict, total=False): + token: str + + expires_at: Annotated[Union[str, datetime], PropertyInfo(alias="expiresAt", format="iso8601")] + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + host: str + + refresh_token: Annotated[str, PropertyInfo(alias="refreshToken")] + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] + + source: HostAuthenticationTokenSource + + user_id: Annotated[str, PropertyInfo(alias="userId")] diff --git a/src/gitpod/types/runners/configurations/host_authentication_token_create_response.py b/src/gitpod/types/runners/configurations/host_authentication_token_create_response.py new file mode 100644 index 0000000..143bdbb --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel +from .host_authentication_token import HostAuthenticationToken + +__all__ = ["HostAuthenticationTokenCreateResponse"] + + +class HostAuthenticationTokenCreateResponse(BaseModel): + token: HostAuthenticationToken diff --git a/src/gitpod/types/runners/configurations/host_authentication_token_delete_params.py b/src/gitpod/types/runners/configurations/host_authentication_token_delete_params.py new file mode 100644 index 0000000..f7de02b --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token_delete_params.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 TypedDict + +__all__ = ["HostAuthenticationTokenDeleteParams"] + + +class HostAuthenticationTokenDeleteParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/runners/configurations/host_authentication_token_list_params.py b/src/gitpod/types/runners/configurations/host_authentication_token_list_params.py new file mode 100644 index 0000000..2576f40 --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token_list_params.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["HostAuthenticationTokenListParams", "Filter", "Pagination"] + + +class HostAuthenticationTokenListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + + +class Filter(TypedDict, total=False): + runner_id: Annotated[Optional[str], PropertyInfo(alias="runnerId")] + + user_id: Annotated[Optional[str], PropertyInfo(alias="userId")] + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/runners/configurations/host_authentication_token_retrieve_params.py b/src/gitpod/types/runners/configurations/host_authentication_token_retrieve_params.py new file mode 100644 index 0000000..c544285 --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token_retrieve_params.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 TypedDict + +__all__ = ["HostAuthenticationTokenRetrieveParams"] + + +class HostAuthenticationTokenRetrieveParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/runners/configurations/host_authentication_token_retrieve_response.py b/src/gitpod/types/runners/configurations/host_authentication_token_retrieve_response.py new file mode 100644 index 0000000..ee629a1 --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token_retrieve_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel +from .host_authentication_token import HostAuthenticationToken + +__all__ = ["HostAuthenticationTokenRetrieveResponse"] + + +class HostAuthenticationTokenRetrieveResponse(BaseModel): + token: HostAuthenticationToken diff --git a/src/gitpod/types/runners/configurations/host_authentication_token_source.py b/src/gitpod/types/runners/configurations/host_authentication_token_source.py new file mode 100644 index 0000000..c610d07 --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token_source.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["HostAuthenticationTokenSource"] + +HostAuthenticationTokenSource: TypeAlias = Literal[ + "HOST_AUTHENTICATION_TOKEN_SOURCE_UNSPECIFIED", + "HOST_AUTHENTICATION_TOKEN_SOURCE_OAUTH", + "HOST_AUTHENTICATION_TOKEN_SOURCE_PAT", +] diff --git a/src/gitpod/types/runners/configurations/host_authentication_token_update_params.py b/src/gitpod/types/runners/configurations/host_authentication_token_update_params.py new file mode 100644 index 0000000..50dfcd2 --- /dev/null +++ b/src/gitpod/types/runners/configurations/host_authentication_token_update_params.py @@ -0,0 +1,111 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["HostAuthenticationTokenUpdateParams"] + + +class HostAuthenticationTokenUpdateParams(TypedDict, total=False): + id: str + + token: Optional[str] + + expires_at: Annotated[Union[str, datetime, None], PropertyInfo(alias="expiresAt", format="iso8601")] + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + refresh_token: Annotated[Optional[str], PropertyInfo(alias="refreshToken")] diff --git a/src/gitpod/types/runners/configurations/runner_configuration_schema.py b/src/gitpod/types/runners/configurations/runner_configuration_schema.py new file mode 100644 index 0000000..caeccd7 --- /dev/null +++ b/src/gitpod/types/runners/configurations/runner_configuration_schema.py @@ -0,0 +1,217 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import builtins +from typing import List, Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = [ + "RunnerConfigurationSchema", + "EnvironmentClass", + "EnvironmentClassBool", + "EnvironmentClassDisplay", + "EnvironmentClassEnum", + "EnvironmentClassEnumDefaultValue", + "EnvironmentClassEnumPossibleValue", + "EnvironmentClassInt", + "EnvironmentClassString", + "RunnerConfig", + "RunnerConfigBool", + "RunnerConfigDisplay", + "RunnerConfigEnum", + "RunnerConfigEnumDefaultValue", + "RunnerConfigEnumPossibleValue", + "RunnerConfigInt", + "RunnerConfigString", + "Scm", + "ScmOAuth", + "ScmPat", +] + + +class EnvironmentClassBool(BaseModel): + default: Optional[bool] = None + + +class EnvironmentClassDisplay(BaseModel): + default: Optional[str] = None + + +class EnvironmentClassEnumDefaultValue(BaseModel): + detail: Optional[str] = None + + subtitle: Optional[str] = None + + title: Optional[str] = None + + +class EnvironmentClassEnumPossibleValue(BaseModel): + detail: Optional[str] = None + + subtitle: Optional[str] = None + + title: Optional[str] = None + + +class EnvironmentClassEnum(BaseModel): + default: Optional[str] = None + """deprecated, will be removed, use default_value instead""" + + default_value: Optional[EnvironmentClassEnumDefaultValue] = FieldInfo(alias="defaultValue", default=None) + + possible_values: Optional[List[EnvironmentClassEnumPossibleValue]] = FieldInfo(alias="possibleValues", default=None) + + values: Optional[List[str]] = None + """deprecated, will be removed, use possible_values instead""" + + +class EnvironmentClassInt(BaseModel): + default: Optional[int] = None + + max: Optional[int] = None + + min: Optional[int] = None + + +class EnvironmentClassString(BaseModel): + default: Optional[str] = None + + pattern: Optional[str] = None + + +class EnvironmentClass(BaseModel): + id: Optional[str] = None + + bool: Optional[EnvironmentClassBool] = None + + description: Optional[str] = None + + display: Optional[EnvironmentClassDisplay] = None + + enum: Optional[EnvironmentClassEnum] = None + + int: Optional[EnvironmentClassInt] = None + + name: Optional[str] = None + + required: Optional[builtins.bool] = None + + secret: Optional[builtins.bool] = None + + string: Optional[EnvironmentClassString] = None + + +class RunnerConfigBool(BaseModel): + default: Optional[bool] = None + + +class RunnerConfigDisplay(BaseModel): + default: Optional[str] = None + + +class RunnerConfigEnumDefaultValue(BaseModel): + detail: Optional[str] = None + + subtitle: Optional[str] = None + + title: Optional[str] = None + + +class RunnerConfigEnumPossibleValue(BaseModel): + detail: Optional[str] = None + + subtitle: Optional[str] = None + + title: Optional[str] = None + + +class RunnerConfigEnum(BaseModel): + default: Optional[str] = None + """deprecated, will be removed, use default_value instead""" + + default_value: Optional[RunnerConfigEnumDefaultValue] = FieldInfo(alias="defaultValue", default=None) + + possible_values: Optional[List[RunnerConfigEnumPossibleValue]] = FieldInfo(alias="possibleValues", default=None) + + values: Optional[List[str]] = None + """deprecated, will be removed, use possible_values instead""" + + +class RunnerConfigInt(BaseModel): + default: Optional[int] = None + + max: Optional[int] = None + + min: Optional[int] = None + + +class RunnerConfigString(BaseModel): + default: Optional[str] = None + + pattern: Optional[str] = None + + +class RunnerConfig(BaseModel): + id: Optional[str] = None + + bool: Optional[RunnerConfigBool] = None + + description: Optional[str] = None + + display: Optional[RunnerConfigDisplay] = None + + enum: Optional[RunnerConfigEnum] = None + + int: Optional[RunnerConfigInt] = None + + name: Optional[str] = None + + required: Optional[builtins.bool] = None + + secret: Optional[builtins.bool] = None + + string: Optional[RunnerConfigString] = None + + +class ScmOAuth(BaseModel): + callback_url: Optional[str] = FieldInfo(alias="callbackUrl", default=None) + """ + callback_url is the URL the OAuth app will redirect to after the user has + authenticated. + """ + + +class ScmPat(BaseModel): + description: Optional[str] = None + """description is a human-readable description of the PAT.""" + + docs_link: Optional[str] = FieldInfo(alias="docsLink", default=None) + """ + docs_link is a link to the documentation on how to create a PAT for this SCM + system. + """ + + +class Scm(BaseModel): + default_hosts: Optional[List[str]] = FieldInfo(alias="defaultHosts", default=None) + + name: Optional[str] = None + + oauth: Optional[ScmOAuth] = None + + pat: Optional[ScmPat] = None + + scm_id: Optional[str] = FieldInfo(alias="scmId", default=None) + + +class RunnerConfigurationSchema(BaseModel): + environment_classes: Optional[List[EnvironmentClass]] = FieldInfo(alias="environmentClasses", default=None) + + runner_config: Optional[List[RunnerConfig]] = FieldInfo(alias="runnerConfig", default=None) + + scm: Optional[List[Scm]] = None + + version: Optional[str] = None + """The schema version""" diff --git a/src/gitpod/types/runners/configurations/schema_retrieve_params.py b/src/gitpod/types/runners/configurations/schema_retrieve_params.py new file mode 100644 index 0000000..2988a4a --- /dev/null +++ b/src/gitpod/types/runners/configurations/schema_retrieve_params.py @@ -0,0 +1,13 @@ +# 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__ = ["SchemaRetrieveParams"] + + +class SchemaRetrieveParams(TypedDict, total=False): + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] diff --git a/src/gitpod/types/runners/configurations/schema_retrieve_response.py b/src/gitpod/types/runners/configurations/schema_retrieve_response.py new file mode 100644 index 0000000..64f13c7 --- /dev/null +++ b/src/gitpod/types/runners/configurations/schema_retrieve_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from .runner_configuration_schema import RunnerConfigurationSchema + +__all__ = ["SchemaRetrieveResponse"] + + +class SchemaRetrieveResponse(BaseModel): + schema_: Optional[RunnerConfigurationSchema] = FieldInfo(alias="schema", default=None) diff --git a/src/gitpod/types/runners/configurations/scm_integration.py b/src/gitpod/types/runners/configurations/scm_integration.py new file mode 100644 index 0000000..05841dc --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel +from .scm_integration_oauth_config import ScmIntegrationOAuthConfig + +__all__ = ["ScmIntegration"] + + +class ScmIntegration(BaseModel): + id: Optional[str] = None + """id is the unique identifier of the SCM integration""" + + host: Optional[str] = None + + oauth: Optional[ScmIntegrationOAuthConfig] = None + + pat: Optional[bool] = None + + runner_id: Optional[str] = FieldInfo(alias="runnerId", default=None) + + scm_id: Optional[str] = FieldInfo(alias="scmId", default=None) + """ + scm_id references the scm_id in the runner's configuration schema that this + integration is for + """ diff --git a/src/gitpod/types/runners/configurations/scm_integration_create_params.py b/src/gitpod/types/runners/configurations/scm_integration_create_params.py new file mode 100644 index 0000000..8cbddf0 --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration_create_params.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["ScmIntegrationCreateParams"] + + +class ScmIntegrationCreateParams(TypedDict, total=False): + host: str + + issuer_url: Annotated[Optional[str], PropertyInfo(alias="issuerUrl")] + """ + issuer_url can be set to override the authentication provider URL, if it doesn't + match the SCM host. + """ + + oauth_client_id: Annotated[Optional[str], PropertyInfo(alias="oauthClientId")] + """ + oauth_client_id is the OAuth app's client ID, if OAuth is configured. If + configured, oauth_plaintext_client_secret must also be set. + """ + + oauth_plaintext_client_secret: Annotated[Optional[str], PropertyInfo(alias="oauthPlaintextClientSecret")] + """ + oauth_plaintext_client_secret is the OAuth app's client secret in clear text. + This will first be encrypted with the runner's public key before being stored. + """ + + pat: bool + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] + + scm_id: Annotated[str, PropertyInfo(alias="scmId")] + """ + scm_id references the scm_id in the runner's configuration schema that this + integration is for + """ diff --git a/src/gitpod/types/runners/configurations/scm_integration_create_response.py b/src/gitpod/types/runners/configurations/scm_integration_create_response.py new file mode 100644 index 0000000..b71bc66 --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration_create_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["ScmIntegrationCreateResponse"] + + +class ScmIntegrationCreateResponse(BaseModel): + id: Optional[str] = None + """id is a uniquely generated identifier for the SCM integration""" diff --git a/src/gitpod/types/runners/configurations/scm_integration_delete_params.py b/src/gitpod/types/runners/configurations/scm_integration_delete_params.py new file mode 100644 index 0000000..f2b72fb --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration_delete_params.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 TypedDict + +__all__ = ["ScmIntegrationDeleteParams"] + + +class ScmIntegrationDeleteParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/runners/configurations/scm_integration_list_params.py b/src/gitpod/types/runners/configurations/scm_integration_list_params.py new file mode 100644 index 0000000..649b18a --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration_list_params.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["ScmIntegrationListParams", "Filter", "Pagination"] + + +class ScmIntegrationListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + """pagination contains the pagination options for listing scm integrations""" + + +class Filter(TypedDict, total=False): + runner_ids: Annotated[List[str], PropertyInfo(alias="runnerIds")] + """runner_ids filters the response to only SCM integrations of these Runner IDs""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/runners/configurations/scm_integration_oauth_config.py b/src/gitpod/types/runners/configurations/scm_integration_oauth_config.py new file mode 100644 index 0000000..f113775 --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration_oauth_config.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = ["ScmIntegrationOAuthConfig"] + + +class ScmIntegrationOAuthConfig(BaseModel): + client_id: Optional[str] = FieldInfo(alias="clientId", default=None) + """client_id is the OAuth app's client ID in clear text.""" + + encrypted_client_secret: Optional[str] = FieldInfo(alias="encryptedClientSecret", default=None) + """ + encrypted_client_secret is the OAuth app's secret encrypted with the runner's + public key. + """ + + issuer_url: Optional[str] = FieldInfo(alias="issuerUrl", default=None) + """ + issuer_url is used to override the authentication provider URL, if it doesn't + match the SCM host. + + +optional if not set, this account is owned by the installation. + """ diff --git a/src/gitpod/types/runners/configurations/scm_integration_retrieve_params.py b/src/gitpod/types/runners/configurations/scm_integration_retrieve_params.py new file mode 100644 index 0000000..d39fe2e --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration_retrieve_params.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 TypedDict + +__all__ = ["ScmIntegrationRetrieveParams"] + + +class ScmIntegrationRetrieveParams(TypedDict, total=False): + id: str diff --git a/src/gitpod/types/runners/configurations/scm_integration_retrieve_response.py b/src/gitpod/types/runners/configurations/scm_integration_retrieve_response.py new file mode 100644 index 0000000..d19d32d --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration_retrieve_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel +from .scm_integration import ScmIntegration + +__all__ = ["ScmIntegrationRetrieveResponse"] + + +class ScmIntegrationRetrieveResponse(BaseModel): + integration: Optional[ScmIntegration] = None diff --git a/src/gitpod/types/runners/configurations/scm_integration_update_params.py b/src/gitpod/types/runners/configurations/scm_integration_update_params.py new file mode 100644 index 0000000..706496d --- /dev/null +++ b/src/gitpod/types/runners/configurations/scm_integration_update_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["ScmIntegrationUpdateParams"] + + +class ScmIntegrationUpdateParams(TypedDict, total=False): + id: str + + issuer_url: Annotated[Optional[str], PropertyInfo(alias="issuerUrl")] + """ + issuer_url can be set to override the authentication provider URL, if it doesn't + match the SCM host. + """ + + oauth_client_id: Annotated[Optional[str], PropertyInfo(alias="oauthClientId")] + """ + oauth_client_id can be set to update the OAuth app's client ID. If an empty + string is set, the OAuth configuration will be removed (regardless of whether a + client secret is set), and any existing Host Authentication Tokens for the SCM + integration's runner and host that were created using the OAuth app will be + deleted. This might lead to users being unable to access their repositories + until they re-authenticate. + """ + + oauth_plaintext_client_secret: Annotated[Optional[str], PropertyInfo(alias="oauthPlaintextClientSecret")] + """ + oauth_plaintext_client_secret can be set to update the OAuth app's client + secret. The cleartext secret will be encrypted with the runner's public key + before being stored. + """ + + pat: Optional[bool] + """ + pat can be set to enable or disable Personal Access Tokens support. When + disabling PATs, any existing Host Authentication Tokens for the SCM + integration's runner and host that were created using a PAT will be deleted. + This might lead to users being unable to access their repositories until they + re-authenticate. + """ diff --git a/src/gitpod/types/runners/environment_class_validation_result.py b/src/gitpod/types/runners/environment_class_validation_result.py new file mode 100644 index 0000000..3b7e146 --- /dev/null +++ b/src/gitpod/types/runners/environment_class_validation_result.py @@ -0,0 +1,20 @@ +# 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 +from .field_validation_error import FieldValidationError + +__all__ = ["EnvironmentClassValidationResult"] + + +class EnvironmentClassValidationResult(BaseModel): + configuration_errors: Optional[List[FieldValidationError]] = FieldInfo(alias="configurationErrors", default=None) + + description_error: Optional[str] = FieldInfo(alias="descriptionError", default=None) + + display_name_error: Optional[str] = FieldInfo(alias="displayNameError", default=None) + + valid: Optional[bool] = None diff --git a/src/gitpod/types/runners/field_validation_error.py b/src/gitpod/types/runners/field_validation_error.py new file mode 100644 index 0000000..6db05ce --- /dev/null +++ b/src/gitpod/types/runners/field_validation_error.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 + +__all__ = ["FieldValidationError"] + + +class FieldValidationError(BaseModel): + error: Optional[str] = None + + key: Optional[str] = None diff --git a/src/gitpod/types/runners/policy_create_params.py b/src/gitpod/types/runners/policy_create_params.py new file mode 100644 index 0000000..5391627 --- /dev/null +++ b/src/gitpod/types/runners/policy_create_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 +from .runner_role import RunnerRole + +__all__ = ["PolicyCreateParams"] + + +class PolicyCreateParams(TypedDict, total=False): + group_id: Annotated[str, PropertyInfo(alias="groupId")] + """group_id specifies the group_id identifier""" + + role: RunnerRole + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] + """runner_id specifies the project identifier""" diff --git a/src/gitpod/types/runners/policy_create_response.py b/src/gitpod/types/runners/policy_create_response.py new file mode 100644 index 0000000..946e4c8 --- /dev/null +++ b/src/gitpod/types/runners/policy_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .runner_policy import RunnerPolicy + +__all__ = ["PolicyCreateResponse"] + + +class PolicyCreateResponse(BaseModel): + policy: RunnerPolicy diff --git a/src/gitpod/types/runners/policy_delete_params.py b/src/gitpod/types/runners/policy_delete_params.py new file mode 100644 index 0000000..d77deca --- /dev/null +++ b/src/gitpod/types/runners/policy_delete_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 Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["PolicyDeleteParams"] + + +class PolicyDeleteParams(TypedDict, total=False): + group_id: Annotated[str, PropertyInfo(alias="groupId")] + """group_id specifies the group_id identifier""" + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] + """runner_id specifies the project identifier""" diff --git a/src/gitpod/types/runners/policy_list_params.py b/src/gitpod/types/runners/policy_list_params.py new file mode 100644 index 0000000..8317d42 --- /dev/null +++ b/src/gitpod/types/runners/policy_list_params.py @@ -0,0 +1,35 @@ +# 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__ = ["PolicyListParams", "Pagination"] + + +class PolicyListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + pagination: Pagination + """pagination contains the pagination options for listing project policies""" + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] + """runner_id specifies the project identifier""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/runners/policy_update_params.py b/src/gitpod/types/runners/policy_update_params.py new file mode 100644 index 0000000..71066d2 --- /dev/null +++ b/src/gitpod/types/runners/policy_update_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 +from .runner_role import RunnerRole + +__all__ = ["PolicyUpdateParams"] + + +class PolicyUpdateParams(TypedDict, total=False): + group_id: Annotated[str, PropertyInfo(alias="groupId")] + """group_id specifies the group_id identifier""" + + role: RunnerRole + + runner_id: Annotated[str, PropertyInfo(alias="runnerId")] + """runner_id specifies the project identifier""" diff --git a/src/gitpod/types/runners/policy_update_response.py b/src/gitpod/types/runners/policy_update_response.py new file mode 100644 index 0000000..7d2094c --- /dev/null +++ b/src/gitpod/types/runners/policy_update_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .runner_policy import RunnerPolicy + +__all__ = ["PolicyUpdateResponse"] + + +class PolicyUpdateResponse(BaseModel): + policy: RunnerPolicy diff --git a/src/gitpod/types/runners/runner_policy.py b/src/gitpod/types/runners/runner_policy.py new file mode 100644 index 0000000..c107db4 --- /dev/null +++ b/src/gitpod/types/runners/runner_policy.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .runner_role import RunnerRole + +__all__ = ["RunnerPolicy"] + + +class RunnerPolicy(BaseModel): + group_id: Optional[str] = FieldInfo(alias="groupId", default=None) + + role: Optional[RunnerRole] = None + """role is the role assigned to the group""" diff --git a/src/gitpod/types/runners/runner_role.py b/src/gitpod/types/runners/runner_role.py new file mode 100644 index 0000000..b4e95a1 --- /dev/null +++ b/src/gitpod/types/runners/runner_role.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__ = ["RunnerRole"] + +RunnerRole: TypeAlias = Literal["RUNNER_ROLE_UNSPECIFIED", "RUNNER_ROLE_ADMIN", "RUNNER_ROLE_USER"] diff --git a/src/gitpod/types/runners/scm_integration_validation_result.py b/src/gitpod/types/runners/scm_integration_validation_result.py new file mode 100644 index 0000000..3a99c80 --- /dev/null +++ b/src/gitpod/types/runners/scm_integration_validation_result.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["ScmIntegrationValidationResult"] + + +class ScmIntegrationValidationResult(BaseModel): + host_error: Optional[str] = FieldInfo(alias="hostError", default=None) + + oauth_error: Optional[str] = FieldInfo(alias="oauthError", default=None) + + pat_error: Optional[str] = FieldInfo(alias="patError", default=None) + + scm_id_error: Optional[str] = FieldInfo(alias="scmIdError", default=None) + + valid: Optional[bool] = None diff --git a/src/gitpod/types/secret.py b/src/gitpod/types/secret.py new file mode 100644 index 0000000..f7bdd15 --- /dev/null +++ b/src/gitpod/types/secret.py @@ -0,0 +1,223 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .secret_scope import SecretScope +from .shared.subject import Subject + +__all__ = ["Secret"] + + +class Secret(BaseModel): + id: Optional[str] = None + + container_registry_basic_auth_host: Optional[str] = FieldInfo(alias="containerRegistryBasicAuthHost", default=None) + """secret will be mounted as a registry secret""" + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + creator: Optional[Subject] = None + """creator is the identity of the creator of the secret""" + + environment_variable: Optional[bool] = FieldInfo(alias="environmentVariable", default=None) + """ + secret will be created as an Environment Variable with the same name as the + secret + """ + + file_path: Optional[str] = FieldInfo(alias="filePath", default=None) + """absolute path to the file where the secret is mounted""" + + name: Optional[str] = None + """Name of the secret for humans.""" + + project_id: Optional[str] = FieldInfo(alias="projectId", default=None) + """The Project ID this Secret belongs to Deprecated: use scope instead""" + + scope: Optional[SecretScope] = None + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ diff --git a/src/gitpod/types/secret_create_params.py b/src/gitpod/types/secret_create_params.py new file mode 100644 index 0000000..61487b0 --- /dev/null +++ b/src/gitpod/types/secret_create_params.py @@ -0,0 +1,47 @@ +# 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 +from .secret_scope_param import SecretScopeParam + +__all__ = ["SecretCreateParams"] + + +class SecretCreateParams(TypedDict, total=False): + container_registry_basic_auth_host: Annotated[str, PropertyInfo(alias="containerRegistryBasicAuthHost")] + """ + secret will be mounted as a docker config in the environment VM, mount will have + the docker registry host + """ + + environment_variable: Annotated[bool, PropertyInfo(alias="environmentVariable")] + """ + secret will be created as an Environment Variable with the same name as the + secret + """ + + file_path: Annotated[str, PropertyInfo(alias="filePath")] + """ + absolute path to the file where the secret is mounted value must be an absolute + path (start with a /): + + ``` + this.matches('^/(?:[^/]*/)*.*$') + ``` + """ + + name: str + + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """ + project_id is the ProjectID this Secret belongs to Deprecated: use scope instead + """ + + scope: SecretScopeParam + """scope is the scope of the secret""" + + value: str + """value is the plaintext value of the secret""" diff --git a/src/gitpod/types/secret_create_response.py b/src/gitpod/types/secret_create_response.py new file mode 100644 index 0000000..bf7c768 --- /dev/null +++ b/src/gitpod/types/secret_create_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .secret import Secret +from .._models import BaseModel + +__all__ = ["SecretCreateResponse"] + + +class SecretCreateResponse(BaseModel): + secret: Optional[Secret] = None diff --git a/src/gitpod/types/secret_delete_params.py b/src/gitpod/types/secret_delete_params.py new file mode 100644 index 0000000..99d8bb6 --- /dev/null +++ b/src/gitpod/types/secret_delete_params.py @@ -0,0 +1,13 @@ +# 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__ = ["SecretDeleteParams"] + + +class SecretDeleteParams(TypedDict, total=False): + secret_id: Annotated[str, PropertyInfo(alias="secretId")] diff --git a/src/gitpod/types/secret_get_value_params.py b/src/gitpod/types/secret_get_value_params.py new file mode 100644 index 0000000..7fbab3d --- /dev/null +++ b/src/gitpod/types/secret_get_value_params.py @@ -0,0 +1,13 @@ +# 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__ = ["SecretGetValueParams"] + + +class SecretGetValueParams(TypedDict, total=False): + secret_id: Annotated[str, PropertyInfo(alias="secretId")] diff --git a/src/gitpod/types/secret_get_value_response.py b/src/gitpod/types/secret_get_value_response.py new file mode 100644 index 0000000..80a70ac --- /dev/null +++ b/src/gitpod/types/secret_get_value_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["SecretGetValueResponse"] + + +class SecretGetValueResponse(BaseModel): + value: Optional[str] = None diff --git a/src/gitpod/types/secret_list_params.py b/src/gitpod/types/secret_list_params.py new file mode 100644 index 0000000..44ab4bd --- /dev/null +++ b/src/gitpod/types/secret_list_params.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo +from .secret_scope_param import SecretScopeParam + +__all__ = ["SecretListParams", "Filter", "Pagination"] + + +class SecretListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + """pagination contains the pagination options for listing environments""" + + +class Filter(TypedDict, total=False): + project_ids: Annotated[List[str], PropertyInfo(alias="projectIds")] + """ + project_ids filters the response to only Secrets used by these Project IDs + Deprecated: use scope instead. Values in project_ids will be ignored. + """ + + scope: SecretScopeParam + """scope is the scope of the secrets to list""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/secret_scope.py b/src/gitpod/types/secret_scope.py new file mode 100644 index 0000000..0c5bc66 --- /dev/null +++ b/src/gitpod/types/secret_scope.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["SecretScope"] + + +class SecretScope(BaseModel): + project_id: Optional[str] = FieldInfo(alias="projectId", default=None) + """project_id is the Project 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 new file mode 100644 index 0000000..85ee9a4 --- /dev/null +++ b/src/gitpod/types/secret_scope_param.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 Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["SecretScopeParam"] + + +class SecretScopeParam(TypedDict, total=False): + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """project_id is the Project 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/secret_update_value_params.py b/src/gitpod/types/secret_update_value_params.py new file mode 100644 index 0000000..0195afc --- /dev/null +++ b/src/gitpod/types/secret_update_value_params.py @@ -0,0 +1,16 @@ +# 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__ = ["SecretUpdateValueParams"] + + +class SecretUpdateValueParams(TypedDict, total=False): + secret_id: Annotated[str, PropertyInfo(alias="secretId")] + + value: str + """value is the plaintext value of the secret""" diff --git a/src/gitpod/types/shared/__init__.py b/src/gitpod/types/shared/__init__.py new file mode 100644 index 0000000..4a5d70a --- /dev/null +++ b/src/gitpod/types/shared/__init__.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .task import Task as Task +from .gateway import Gateway as Gateway +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 .error_code import ErrorCode as ErrorCode +from .field_value import FieldValue as FieldValue +from .user_status import UserStatus as UserStatus +from .task_metadata import TaskMetadata as TaskMetadata +from .task_execution import TaskExecution as TaskExecution +from .environment_class import EnvironmentClass as EnvironmentClass +from .organization_role import OrganizationRole as OrganizationRole +from .automation_trigger import AutomationTrigger as AutomationTrigger +from .task_execution_spec import TaskExecutionSpec as TaskExecutionSpec +from .task_execution_phase import TaskExecutionPhase as TaskExecutionPhase +from .task_execution_status import TaskExecutionStatus as TaskExecutionStatus +from .task_execution_metadata import TaskExecutionMetadata as TaskExecutionMetadata diff --git a/src/gitpod/types/shared/automation_trigger.py b/src/gitpod/types/shared/automation_trigger.py new file mode 100644 index 0000000..2b5eba3 --- /dev/null +++ b/src/gitpod/types/shared/automation_trigger.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["AutomationTrigger"] + + +class AutomationTrigger(BaseModel): + manual: Optional[bool] = None + + post_devcontainer_start: Optional[bool] = FieldInfo(alias="postDevcontainerStart", default=None) + + post_environment_start: Optional[bool] = FieldInfo(alias="postEnvironmentStart", default=None) diff --git a/src/gitpod/types/shared/environment_class.py b/src/gitpod/types/shared/environment_class.py new file mode 100644 index 0000000..7539415 --- /dev/null +++ b/src/gitpod/types/shared/environment_class.py @@ -0,0 +1,36 @@ +# 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 +from .field_value import FieldValue + +__all__ = ["EnvironmentClass"] + + +class EnvironmentClass(BaseModel): + id: str + """id is the unique identifier of the environment class""" + + runner_id: str = FieldInfo(alias="runnerId") + """ + runner_id is the unique identifier of the runner the environment class belongs + to + """ + + configuration: Optional[List[FieldValue]] = None + """configuration describes the configuration of the environment class""" + + description: Optional[str] = None + """description is a human readable description of the environment class""" + + display_name: Optional[str] = FieldInfo(alias="displayName", default=None) + """display_name is the human readable name of the environment class""" + + enabled: Optional[bool] = None + """ + enabled indicates whether the environment class can be used to create new + environments. + """ diff --git a/src/gitpod/types/shared/error_code.py b/src/gitpod/types/shared/error_code.py new file mode 100644 index 0000000..316948a --- /dev/null +++ b/src/gitpod/types/shared/error_code.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ErrorCode"] + +ErrorCode: TypeAlias = Literal[ + "canceled", + "unknown", + "invalid_argument", + "deadline_exceeded", + "not_found", + "already_exists", + "permission_denied", + "resource_exhausted", + "failed_precondition", + "aborted", + "out_of_range", + "unimplemented", + "internal", + "unavailable", + "data_loss", + "unauthenticated", +] diff --git a/src/gitpod/types/shared/field_value.py b/src/gitpod/types/shared/field_value.py new file mode 100644 index 0000000..90a9019 --- /dev/null +++ b/src/gitpod/types/shared/field_value.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 + +__all__ = ["FieldValue"] + + +class FieldValue(BaseModel): + key: Optional[str] = None + + value: Optional[str] = None diff --git a/src/gitpod/types/shared/gateway.py b/src/gitpod/types/shared/gateway.py new file mode 100644 index 0000000..cae2976 --- /dev/null +++ b/src/gitpod/types/shared/gateway.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["Gateway"] + + +class Gateway(BaseModel): + name: str + """name is the human-readable name of the gateway. + + name is unique across all gateways. + """ + + url: str + """url of the gateway""" + + region: Optional[str] = None + """region is the geographical region where the gateway is located""" diff --git a/src/gitpod/types/shared/organization_role.py b/src/gitpod/types/shared/organization_role.py new file mode 100644 index 0000000..202e7a3 --- /dev/null +++ b/src/gitpod/types/shared/organization_role.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["OrganizationRole"] + +OrganizationRole: TypeAlias = Literal[ + "ORGANIZATION_ROLE_UNSPECIFIED", "ORGANIZATION_ROLE_ADMIN", "ORGANIZATION_ROLE_MEMBER" +] diff --git a/src/gitpod/types/shared/principal.py b/src/gitpod/types/shared/principal.py new file mode 100644 index 0000000..5300b52 --- /dev/null +++ b/src/gitpod/types/shared/principal.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["Principal"] + +Principal: TypeAlias = Literal[ + "PRINCIPAL_UNSPECIFIED", + "PRINCIPAL_ACCOUNT", + "PRINCIPAL_USER", + "PRINCIPAL_RUNNER", + "PRINCIPAL_ENVIRONMENT", + "PRINCIPAL_SERVICE_ACCOUNT", + "PRINCIPAL_RUNNER_MANAGER", +] diff --git a/src/gitpod/types/shared/runs_on.py b/src/gitpod/types/shared/runs_on.py new file mode 100644 index 0000000..7702279 --- /dev/null +++ b/src/gitpod/types/shared/runs_on.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["RunsOn", "Docker"] + + +class Docker(BaseModel): + environment: Optional[List[str]] = None + + image: Optional[str] = None + + +class RunsOn(BaseModel): + docker: Docker diff --git a/src/gitpod/types/shared/subject.py b/src/gitpod/types/shared/subject.py new file mode 100644 index 0000000..88a258c --- /dev/null +++ b/src/gitpod/types/shared/subject.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .principal import Principal + +__all__ = ["Subject"] + + +class Subject(BaseModel): + id: Optional[str] = None + """id is the UUID of the subject""" + + principal: Optional[Principal] = None + """Principal is the principal of the subject""" diff --git a/src/gitpod/types/shared/task.py b/src/gitpod/types/shared/task.py new file mode 100644 index 0000000..c45bfa6 --- /dev/null +++ b/src/gitpod/types/shared/task.py @@ -0,0 +1,24 @@ +# 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 +from .task_spec import TaskSpec +from .task_metadata import TaskMetadata + +__all__ = ["Task"] + + +class Task(BaseModel): + id: str + + depends_on: Optional[List[str]] = FieldInfo(alias="dependsOn", default=None) + """dependencies specifies the IDs of the automations this task depends on.""" + + environment_id: Optional[str] = FieldInfo(alias="environmentId", default=None) + + metadata: Optional[TaskMetadata] = None + + spec: Optional[TaskSpec] = None diff --git a/src/gitpod/types/shared/task_execution.py b/src/gitpod/types/shared/task_execution.py new file mode 100644 index 0000000..3274176 --- /dev/null +++ b/src/gitpod/types/shared/task_execution.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .task_execution_spec import TaskExecutionSpec +from .task_execution_status import TaskExecutionStatus +from .task_execution_metadata import TaskExecutionMetadata + +__all__ = ["TaskExecution"] + + +class TaskExecution(BaseModel): + id: str + + metadata: Optional[TaskExecutionMetadata] = None + + spec: Optional[TaskExecutionSpec] = None + + status: Optional[TaskExecutionStatus] = None diff --git a/src/gitpod/types/shared/task_execution_metadata.py b/src/gitpod/types/shared/task_execution_metadata.py new file mode 100644 index 0000000..8e72321 --- /dev/null +++ b/src/gitpod/types/shared/task_execution_metadata.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .subject import Subject +from ..._models import BaseModel + +__all__ = ["TaskExecutionMetadata"] + + +class TaskExecutionMetadata(BaseModel): + completed_at: Optional[datetime] = FieldInfo(alias="completedAt", default=None) + """completed_at is the time the task execution was done.""" + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """created_at is the time the task was created.""" + + creator: Optional[Subject] = None + """creator describes the principal who created/started the task run.""" + + environment_id: Optional[str] = FieldInfo(alias="environmentId", default=None) + """environment_id is the ID of the environment in which the task run is executed.""" + + started_at: Optional[datetime] = FieldInfo(alias="startedAt", default=None) + """started_at is the time the task execution actually started to run.""" + + started_by: Optional[str] = FieldInfo(alias="startedBy", default=None) + """started_by describes the trigger that started the task execution.""" + + task_id: Optional[str] = FieldInfo(alias="taskId", default=None) + """task_id is the ID of the main task being executed.""" diff --git a/src/gitpod/types/shared/task_execution_phase.py b/src/gitpod/types/shared/task_execution_phase.py new file mode 100644 index 0000000..84b6f31 --- /dev/null +++ b/src/gitpod/types/shared/task_execution_phase.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["TaskExecutionPhase"] + +TaskExecutionPhase: TypeAlias = Literal[ + "TASK_EXECUTION_PHASE_UNSPECIFIED", + "TASK_EXECUTION_PHASE_PENDING", + "TASK_EXECUTION_PHASE_RUNNING", + "TASK_EXECUTION_PHASE_SUCCEEDED", + "TASK_EXECUTION_PHASE_FAILED", + "TASK_EXECUTION_PHASE_STOPPED", +] diff --git a/src/gitpod/types/shared/task_execution_spec.py b/src/gitpod/types/shared/task_execution_spec.py new file mode 100644 index 0000000..17a4bff --- /dev/null +++ b/src/gitpod/types/shared/task_execution_spec.py @@ -0,0 +1,49 @@ +# 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 +from .task_spec import TaskSpec +from .task_execution_phase import TaskExecutionPhase + +__all__ = ["TaskExecutionSpec", "Plan", "PlanStep", "PlanStepTask"] + + +class PlanStepTask(BaseModel): + id: Optional[str] = None + + spec: Optional[TaskSpec] = None + + +class PlanStep(BaseModel): + id: Optional[str] = None + """ID is the ID of the execution step""" + + depends_on: Optional[List[str]] = FieldInfo(alias="dependsOn", default=None) + + label: Optional[str] = None + + service_id: Optional[str] = FieldInfo(alias="serviceId", default=None) + + task: Optional[PlanStepTask] = None + + +class Plan(BaseModel): + steps: Optional[List[PlanStep]] = None + + +class TaskExecutionSpec(BaseModel): + desired_phase: Optional[TaskExecutionPhase] = FieldInfo(alias="desiredPhase", default=None) + """desired_phase is the phase the task execution should be in. + + Used to stop a running task execution early. + """ + + plan: Optional[List[Plan]] = None + """plan is a list of groups of steps. + + The steps in a group are executed concurrently, while the groups are executed + sequentially. The order of the groups is the order in which they are executed. + """ diff --git a/src/gitpod/types/shared/task_execution_status.py b/src/gitpod/types/shared/task_execution_status.py new file mode 100644 index 0000000..2a4765a --- /dev/null +++ b/src/gitpod/types/shared/task_execution_status.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .task_execution_phase import TaskExecutionPhase + +__all__ = ["TaskExecutionStatus", "Step"] + + +class Step(BaseModel): + id: Optional[str] = None + """ID is the ID of the execution step""" + + failure_message: Optional[str] = FieldInfo(alias="failureMessage", default=None) + """failure_message summarises why the step failed to operate. + + If this is non-empty the step has failed to operate and will likely transition + to a failed state. + """ + + output: Optional[Dict[str, str]] = None + """ + output contains the output of the task execution. setting an output field to + empty string will unset it. + """ + + phase: Optional[TaskExecutionPhase] = None + """phase is the current phase of the execution step""" + + +class TaskExecutionStatus(BaseModel): + failure_message: Optional[str] = FieldInfo(alias="failureMessage", default=None) + """failure_message summarises why the task execution failed to operate. + + If this is non-empty the task execution has failed to operate and will likely + transition to a failed state. + """ + + log_url: Optional[str] = FieldInfo(alias="logUrl", default=None) + """log_url is the URL to the logs of the task's steps. + + If this is empty, the task either has no logs or has not yet started. + """ + + phase: Optional[TaskExecutionPhase] = None + """the phase of a task execution represents the aggregated phase of all steps.""" + + status_version: Optional[str] = FieldInfo(alias="statusVersion", default=None) + """version of the status update. + + Task executions themselves are unversioned, but their status has different + versions. The value of this field has no semantic meaning (e.g. don't interpret + it as as a timestamp), but it can be used to impose a partial order. If + a.status_version < b.status_version then a was the status before b. + """ + + steps: Optional[List[Step]] = None + """steps provides the status for each individual step of the task execution. + + If a step is missing it has not yet started. + """ diff --git a/src/gitpod/types/shared/task_metadata.py b/src/gitpod/types/shared/task_metadata.py new file mode 100644 index 0000000..6a34633 --- /dev/null +++ b/src/gitpod/types/shared/task_metadata.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .subject import Subject +from ..._models import BaseModel +from .automation_trigger import AutomationTrigger + +__all__ = ["TaskMetadata"] + + +class TaskMetadata(BaseModel): + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """created_at is the time the task was created.""" + + creator: Optional[Subject] = None + """creator describes the principal who created the task.""" + + description: Optional[str] = None + """description is a user-facing description for the task. + + It can be used to provide context and documentation for the task. + """ + + name: Optional[str] = None + """name is a user-facing name for the task. + + Unlike the reference, this field is not unique, and not referenced by the + system. This is a short descriptive name for the task. + """ + + reference: Optional[str] = None + """ + reference is a user-facing identifier for the task which must be unique on the + environment. It is used to express dependencies between tasks, and to identify + the task in user interactions (e.g. the CLI). + """ + + triggered_by: Optional[List[AutomationTrigger]] = FieldInfo(alias="triggeredBy", default=None) + """triggered_by is a list of trigger that start the task.""" diff --git a/src/gitpod/types/shared/task_spec.py b/src/gitpod/types/shared/task_spec.py new file mode 100644 index 0000000..c69815f --- /dev/null +++ b/src/gitpod/types/shared/task_spec.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from .runs_on import RunsOn +from ..._models import BaseModel + +__all__ = ["TaskSpec"] + + +class TaskSpec(BaseModel): + command: Optional[str] = None + """command contains the command the task should execute""" + + runs_on: Optional[RunsOn] = FieldInfo(alias="runsOn", default=None) + """runs_on specifies the environment the task should run on.""" diff --git a/src/gitpod/types/shared/user_status.py b/src/gitpod/types/shared/user_status.py new file mode 100644 index 0000000..d13e58c --- /dev/null +++ b/src/gitpod/types/shared/user_status.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +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/src/gitpod/types/shared_params/__init__.py b/src/gitpod/types/shared_params/__init__.py new file mode 100644 index 0000000..51915e7 --- /dev/null +++ b/src/gitpod/types/shared_params/__init__.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +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 .field_value import FieldValue as FieldValue +from .task_metadata import TaskMetadata as TaskMetadata +from .environment_class import EnvironmentClass as EnvironmentClass +from .organization_role import OrganizationRole as OrganizationRole +from .automation_trigger import AutomationTrigger as AutomationTrigger +from .task_execution_phase import TaskExecutionPhase as TaskExecutionPhase diff --git a/src/gitpod/types/shared_params/automation_trigger.py b/src/gitpod/types/shared_params/automation_trigger.py new file mode 100644 index 0000000..173dff4 --- /dev/null +++ b/src/gitpod/types/shared_params/automation_trigger.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 Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["AutomationTrigger"] + + +class AutomationTrigger(TypedDict, total=False): + manual: bool + + post_devcontainer_start: Annotated[bool, PropertyInfo(alias="postDevcontainerStart")] + + post_environment_start: Annotated[bool, PropertyInfo(alias="postEnvironmentStart")] diff --git a/src/gitpod/types/shared_params/environment_class.py b/src/gitpod/types/shared_params/environment_class.py new file mode 100644 index 0000000..b310694 --- /dev/null +++ b/src/gitpod/types/shared_params/environment_class.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo +from .field_value import FieldValue + +__all__ = ["EnvironmentClass"] + + +class EnvironmentClass(TypedDict, total=False): + id: Required[str] + """id is the unique identifier of the environment class""" + + runner_id: Required[Annotated[str, PropertyInfo(alias="runnerId")]] + """ + runner_id is the unique identifier of the runner the environment class belongs + to + """ + + configuration: Iterable[FieldValue] + """configuration describes the configuration of the environment class""" + + description: str + """description is a human readable description of the environment class""" + + display_name: Annotated[str, PropertyInfo(alias="displayName")] + """display_name is the human readable name of the environment class""" + + enabled: bool + """ + enabled indicates whether the environment class can be used to create new + environments. + """ diff --git a/src/gitpod/types/shared_params/field_value.py b/src/gitpod/types/shared_params/field_value.py new file mode 100644 index 0000000..05f28c1 --- /dev/null +++ b/src/gitpod/types/shared_params/field_value.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["FieldValue"] + + +class FieldValue(TypedDict, total=False): + key: str + + value: str diff --git a/src/gitpod/types/shared_params/organization_role.py b/src/gitpod/types/shared_params/organization_role.py new file mode 100644 index 0000000..1c3d4f1 --- /dev/null +++ b/src/gitpod/types/shared_params/organization_role.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__ = ["OrganizationRole"] + +OrganizationRole: TypeAlias = Literal[ + "ORGANIZATION_ROLE_UNSPECIFIED", "ORGANIZATION_ROLE_ADMIN", "ORGANIZATION_ROLE_MEMBER" +] diff --git a/src/gitpod/types/shared_params/principal.py b/src/gitpod/types/shared_params/principal.py new file mode 100644 index 0000000..3cefcfa --- /dev/null +++ b/src/gitpod/types/shared_params/principal.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 Literal, TypeAlias + +__all__ = ["Principal"] + +Principal: TypeAlias = Literal[ + "PRINCIPAL_UNSPECIFIED", + "PRINCIPAL_ACCOUNT", + "PRINCIPAL_USER", + "PRINCIPAL_RUNNER", + "PRINCIPAL_ENVIRONMENT", + "PRINCIPAL_SERVICE_ACCOUNT", + "PRINCIPAL_RUNNER_MANAGER", +] diff --git a/src/gitpod/types/shared_params/runs_on.py b/src/gitpod/types/shared_params/runs_on.py new file mode 100644 index 0000000..55a079f --- /dev/null +++ b/src/gitpod/types/shared_params/runs_on.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Required, TypedDict + +__all__ = ["RunsOn", "Docker"] + + +class Docker(TypedDict, total=False): + environment: List[str] + + image: str + + +class RunsOn(TypedDict, total=False): + docker: Required[Docker] diff --git a/src/gitpod/types/shared_params/subject.py b/src/gitpod/types/shared_params/subject.py new file mode 100644 index 0000000..1c1293b --- /dev/null +++ b/src/gitpod/types/shared_params/subject.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 TypedDict + +from ..shared.principal import Principal + +__all__ = ["Subject"] + + +class Subject(TypedDict, total=False): + id: str + """id is the UUID of the subject""" + + principal: Principal + """Principal is the principal of the subject""" diff --git a/src/gitpod/types/shared_params/task_execution_phase.py b/src/gitpod/types/shared_params/task_execution_phase.py new file mode 100644 index 0000000..60b1bc3 --- /dev/null +++ b/src/gitpod/types/shared_params/task_execution_phase.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypeAlias + +__all__ = ["TaskExecutionPhase"] + +TaskExecutionPhase: TypeAlias = Literal[ + "TASK_EXECUTION_PHASE_UNSPECIFIED", + "TASK_EXECUTION_PHASE_PENDING", + "TASK_EXECUTION_PHASE_RUNNING", + "TASK_EXECUTION_PHASE_SUCCEEDED", + "TASK_EXECUTION_PHASE_FAILED", + "TASK_EXECUTION_PHASE_STOPPED", +] diff --git a/src/gitpod/types/shared_params/task_metadata.py b/src/gitpod/types/shared_params/task_metadata.py new file mode 100644 index 0000000..2523ba6 --- /dev/null +++ b/src/gitpod/types/shared_params/task_metadata.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from .subject import Subject +from ..._utils import PropertyInfo +from .automation_trigger import AutomationTrigger + +__all__ = ["TaskMetadata"] + + +class TaskMetadata(TypedDict, total=False): + created_at: Annotated[Union[str, datetime], PropertyInfo(alias="createdAt", format="iso8601")] + """created_at is the time the task was created.""" + + creator: Subject + """creator describes the principal who created the task.""" + + description: str + """description is a user-facing description for the task. + + It can be used to provide context and documentation for the task. + """ + + name: str + """name is a user-facing name for the task. + + Unlike the reference, this field is not unique, and not referenced by the + system. This is a short descriptive name for the task. + """ + + reference: str + """ + reference is a user-facing identifier for the task which must be unique on the + environment. It is used to express dependencies between tasks, and to identify + the task in user interactions (e.g. the CLI). + """ + + triggered_by: Annotated[Iterable[AutomationTrigger], PropertyInfo(alias="triggeredBy")] + """triggered_by is a list of trigger that start the task.""" diff --git a/src/gitpod/types/shared_params/task_spec.py b/src/gitpod/types/shared_params/task_spec.py new file mode 100644 index 0000000..5f40eef --- /dev/null +++ b/src/gitpod/types/shared_params/task_spec.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from .runs_on import RunsOn +from ..._utils import PropertyInfo + +__all__ = ["TaskSpec"] + + +class TaskSpec(TypedDict, total=False): + command: str + """command contains the command the task should execute""" + + runs_on: Annotated[RunsOn, PropertyInfo(alias="runsOn")] + """runs_on specifies the environment the task should run on.""" diff --git a/src/gitpod/types/usage_list_environment_runtime_records_params.py b/src/gitpod/types/usage_list_environment_runtime_records_params.py new file mode 100644 index 0000000..3f97243 --- /dev/null +++ b/src/gitpod/types/usage_list_environment_runtime_records_params.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["UsageListEnvironmentRuntimeRecordsParams", "Filter", "FilterDateRange", "Pagination"] + + +class UsageListEnvironmentRuntimeRecordsParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + """Filter options.""" + + pagination: Pagination + """Pagination options.""" + + +class FilterDateRange(TypedDict, total=False): + end_time: Required[Annotated[Union[str, datetime], PropertyInfo(alias="endTime", format="iso8601")]] + """End time of the date range (exclusive).""" + + start_time: Required[Annotated[Union[str, datetime], PropertyInfo(alias="startTime", format="iso8601")]] + """Start time of the date range (inclusive).""" + + +class Filter(TypedDict, total=False): + date_range: Required[Annotated[FilterDateRange, PropertyInfo(alias="dateRange")]] + """Date range to query runtime records within.""" + + project_id: Annotated[str, PropertyInfo(alias="projectId")] + """Optional project ID to filter runtime records by.""" + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/user.py b/src/gitpod/types/user.py new file mode 100644 index 0000000..a8ce63f --- /dev/null +++ b/src/gitpod/types/user.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.user_status import UserStatus + +__all__ = ["User"] + + +class User(BaseModel): + id: str + """id is a UUID of the user""" + + avatar_url: Optional[str] = FieldInfo(alias="avatarUrl", default=None) + """avatar_url is a link to the user avatar""" + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """created_at is the creation time""" + + name: Optional[str] = None + """name is the full name of the user""" + + organization_id: Optional[str] = FieldInfo(alias="organizationId", default=None) + """organization_id is the id of the organization this account is owned by. + + +optional if not set, this account is owned by the installation. + """ + + status: Optional[UserStatus] = None + """status is the status the user is in""" diff --git a/src/gitpod/types/user_get_authenticated_user_params.py b/src/gitpod/types/user_get_authenticated_user_params.py new file mode 100644 index 0000000..2b65cbb --- /dev/null +++ b/src/gitpod/types/user_get_authenticated_user_params.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 TypedDict + +__all__ = ["UserGetAuthenticatedUserParams"] + + +class UserGetAuthenticatedUserParams(TypedDict, total=False): + empty: bool diff --git a/src/gitpod/types/user_get_authenticated_user_response.py b/src/gitpod/types/user_get_authenticated_user_response.py new file mode 100644 index 0000000..8610b45 --- /dev/null +++ b/src/gitpod/types/user_get_authenticated_user_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .user import User +from .._models import BaseModel + +__all__ = ["UserGetAuthenticatedUserResponse"] + + +class UserGetAuthenticatedUserResponse(BaseModel): + user: User diff --git a/src/gitpod/types/user_set_suspended_params.py b/src/gitpod/types/user_set_suspended_params.py new file mode 100644 index 0000000..1a4e3d9 --- /dev/null +++ b/src/gitpod/types/user_set_suspended_params.py @@ -0,0 +1,15 @@ +# 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__ = ["UserSetSuspendedParams"] + + +class UserSetSuspendedParams(TypedDict, total=False): + suspended: bool + + user_id: Annotated[str, PropertyInfo(alias="userId")] diff --git a/src/gitpod/types/users/__init__.py b/src/gitpod/types/users/__init__.py new file mode 100644 index 0000000..8145891 --- /dev/null +++ b/src/gitpod/types/users/__init__.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .pat_get_params import PatGetParams as PatGetParams +from .pat_list_params import PatListParams as PatListParams +from .pat_get_response import PatGetResponse as PatGetResponse +from .pat_delete_params import PatDeleteParams as PatDeleteParams +from .dotfile_get_params import DotfileGetParams as DotfileGetParams +from .dotfile_set_params import DotfileSetParams as DotfileSetParams +from .dotfile_get_response import DotfileGetResponse as DotfileGetResponse +from .personal_access_token import PersonalAccessToken as PersonalAccessToken +from .dotfiles_configuration import DotfilesConfiguration as DotfilesConfiguration diff --git a/src/gitpod/types/users/dotfile_get_params.py b/src/gitpod/types/users/dotfile_get_params.py new file mode 100644 index 0000000..f9272c3 --- /dev/null +++ b/src/gitpod/types/users/dotfile_get_params.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 TypedDict + +__all__ = ["DotfileGetParams"] + + +class DotfileGetParams(TypedDict, total=False): + empty: bool diff --git a/src/gitpod/types/users/dotfile_get_response.py b/src/gitpod/types/users/dotfile_get_response.py new file mode 100644 index 0000000..4cb5e02 --- /dev/null +++ b/src/gitpod/types/users/dotfile_get_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from .dotfiles_configuration import DotfilesConfiguration + +__all__ = ["DotfileGetResponse"] + + +class DotfileGetResponse(BaseModel): + dotfiles_configuration: DotfilesConfiguration = FieldInfo(alias="dotfilesConfiguration") diff --git a/src/gitpod/types/users/dotfile_set_params.py b/src/gitpod/types/users/dotfile_set_params.py new file mode 100644 index 0000000..21d63bd --- /dev/null +++ b/src/gitpod/types/users/dotfile_set_params.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 TypedDict + +__all__ = ["DotfileSetParams"] + + +class DotfileSetParams(TypedDict, total=False): + repository: str diff --git a/src/gitpod/types/users/dotfiles_configuration.py b/src/gitpod/types/users/dotfiles_configuration.py new file mode 100644 index 0000000..c5595be --- /dev/null +++ b/src/gitpod/types/users/dotfiles_configuration.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["DotfilesConfiguration"] + + +class DotfilesConfiguration(BaseModel): + repository: Optional[str] = None + """The URL of a dotfiles repository.""" diff --git a/src/gitpod/types/users/pat_delete_params.py b/src/gitpod/types/users/pat_delete_params.py new file mode 100644 index 0000000..990e660 --- /dev/null +++ b/src/gitpod/types/users/pat_delete_params.py @@ -0,0 +1,13 @@ +# 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__ = ["PatDeleteParams"] + + +class PatDeleteParams(TypedDict, total=False): + personal_access_token_id: Annotated[str, PropertyInfo(alias="personalAccessTokenId")] diff --git a/src/gitpod/types/users/pat_get_params.py b/src/gitpod/types/users/pat_get_params.py new file mode 100644 index 0000000..6851c57 --- /dev/null +++ b/src/gitpod/types/users/pat_get_params.py @@ -0,0 +1,13 @@ +# 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__ = ["PatGetParams"] + + +class PatGetParams(TypedDict, total=False): + personal_access_token_id: Annotated[str, PropertyInfo(alias="personalAccessTokenId")] diff --git a/src/gitpod/types/users/pat_get_response.py b/src/gitpod/types/users/pat_get_response.py new file mode 100644 index 0000000..5c0b2a0 --- /dev/null +++ b/src/gitpod/types/users/pat_get_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .personal_access_token import PersonalAccessToken + +__all__ = ["PatGetResponse"] + + +class PatGetResponse(BaseModel): + pat: PersonalAccessToken diff --git a/src/gitpod/types/users/pat_list_params.py b/src/gitpod/types/users/pat_list_params.py new file mode 100644 index 0000000..b03f6d6 --- /dev/null +++ b/src/gitpod/types/users/pat_list_params.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["PatListParams", "Filter", "Pagination"] + + +class PatListParams(TypedDict, total=False): + token: str + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + filter: Filter + + pagination: Pagination + + +class Filter(TypedDict, total=False): + user_ids: Annotated[List[str], PropertyInfo(alias="userIds")] + """ + creator_ids filters the response to only Environments created by specified + members + """ + + +class Pagination(TypedDict, total=False): + token: str + """ + Token for the next set of results that was returned as next_token of a + PaginationResponse + """ + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + """Page size is the maximum number of results to retrieve per page. Defaults to 25. + + Maximum 100. + """ diff --git a/src/gitpod/types/users/personal_access_token.py b/src/gitpod/types/users/personal_access_token.py new file mode 100644 index 0000000..c094c3c --- /dev/null +++ b/src/gitpod/types/users/personal_access_token.py @@ -0,0 +1,297 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel +from ..shared.subject import Subject + +__all__ = ["PersonalAccessToken"] + + +class PersonalAccessToken(BaseModel): + id: Optional[str] = None + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + creator: Optional[Subject] = None + + description: Optional[str] = None + + expires_at: Optional[datetime] = FieldInfo(alias="expiresAt", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + last_used: Optional[datetime] = FieldInfo(alias="lastUsed", default=None) + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at nanosecond + resolution. The count is relative to an epoch at UTC midnight on January 1, + 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a + [24-hour linear smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + zero-padded to two digits each. The fractional seconds, which can go up to 9 + digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + serializer should always use UTC (as indicated by "Z") when printing the + Timestamp type and a proto3 JSON parser should be able to accept both UTC and + other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted to + this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + Joda Time's + [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + to obtain a formatter capable of generating timestamps in this format. + """ + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/__init__.py b/tests/api_resources/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/environments/__init__.py b/tests/api_resources/environments/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/environments/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/environments/automations/__init__.py b/tests/api_resources/environments/automations/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/environments/automations/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/environments/automations/tasks/__init__.py b/tests/api_resources/environments/automations/tasks/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/environments/automations/tasks/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/environments/automations/tasks/test_executions.py b/tests/api_resources/environments/automations/tasks/test_executions.py new file mode 100644 index 0000000..aa72d5f --- /dev/null +++ b/tests/api_resources/environments/automations/tasks/test_executions.py @@ -0,0 +1,268 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncTaskExecutionsPage, AsyncTaskExecutionsPage +from gitpod.types.shared import TaskExecution +from gitpod.types.environments.automations.tasks import ( + ExecutionRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestExecutions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + execution = client.environments.automations.tasks.executions.retrieve() + assert_matches_type(ExecutionRetrieveResponse, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + execution = client.environments.automations.tasks.executions.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(ExecutionRetrieveResponse, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.executions.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = response.parse() + assert_matches_type(ExecutionRetrieveResponse, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.environments.automations.tasks.executions.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = response.parse() + assert_matches_type(ExecutionRetrieveResponse, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + execution = client.environments.automations.tasks.executions.list() + assert_matches_type(SyncTaskExecutionsPage[TaskExecution], execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + execution = client.environments.automations.tasks.executions.list( + token="token", + page_size=0, + filter={ + "environment_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "phases": ["TASK_EXECUTION_PHASE_RUNNING", "TASK_EXECUTION_PHASE_FAILED"], + "task_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "task_references": ["string"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncTaskExecutionsPage[TaskExecution], execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.executions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = response.parse() + assert_matches_type(SyncTaskExecutionsPage[TaskExecution], execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.environments.automations.tasks.executions.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = response.parse() + assert_matches_type(SyncTaskExecutionsPage[TaskExecution], execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_stop(self, client: Gitpod) -> None: + execution = client.environments.automations.tasks.executions.stop() + assert_matches_type(object, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_stop_with_all_params(self, client: Gitpod) -> None: + execution = client.environments.automations.tasks.executions.stop( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_stop(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.executions.with_raw_response.stop() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = response.parse() + assert_matches_type(object, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_stop(self, client: Gitpod) -> None: + with client.environments.automations.tasks.executions.with_streaming_response.stop() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = response.parse() + assert_matches_type(object, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncExecutions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + execution = await async_client.environments.automations.tasks.executions.retrieve() + assert_matches_type(ExecutionRetrieveResponse, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + execution = await async_client.environments.automations.tasks.executions.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(ExecutionRetrieveResponse, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.executions.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = await response.parse() + assert_matches_type(ExecutionRetrieveResponse, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with ( + async_client.environments.automations.tasks.executions.with_streaming_response.retrieve() + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = await response.parse() + assert_matches_type(ExecutionRetrieveResponse, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + execution = await async_client.environments.automations.tasks.executions.list() + assert_matches_type(AsyncTaskExecutionsPage[TaskExecution], execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + execution = await async_client.environments.automations.tasks.executions.list( + token="token", + page_size=0, + filter={ + "environment_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "phases": ["TASK_EXECUTION_PHASE_RUNNING", "TASK_EXECUTION_PHASE_FAILED"], + "task_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "task_references": ["string"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncTaskExecutionsPage[TaskExecution], execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.executions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = await response.parse() + assert_matches_type(AsyncTaskExecutionsPage[TaskExecution], execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.tasks.executions.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = await response.parse() + assert_matches_type(AsyncTaskExecutionsPage[TaskExecution], execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_stop(self, async_client: AsyncGitpod) -> None: + execution = await async_client.environments.automations.tasks.executions.stop() + assert_matches_type(object, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_stop_with_all_params(self, async_client: AsyncGitpod) -> None: + execution = await async_client.environments.automations.tasks.executions.stop( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_stop(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.executions.with_raw_response.stop() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = await response.parse() + assert_matches_type(object, execution, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_stop(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.tasks.executions.with_streaming_response.stop() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = await response.parse() + assert_matches_type(object, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/environments/automations/test_services.py b/tests/api_resources/environments/automations/test_services.py new file mode 100644 index 0000000..64db132 --- /dev/null +++ b/tests/api_resources/environments/automations/test_services.py @@ -0,0 +1,688 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod._utils import parse_datetime +from gitpod.pagination import SyncServicesPage, AsyncServicesPage +from gitpod.types.environments.automations import ( + Service, + ServiceCreateResponse, + ServiceRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestServices: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + service = client.environments.automations.services.create() + assert_matches_type(ServiceCreateResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + service = client.environments.automations.services.create( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + metadata={ + "created_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "creator": { + "id": "id", + "principal": "PRINCIPAL_UNSPECIFIED", + }, + "description": "Runs the development web server", + "name": "Web Server", + "reference": "web-server", + "triggered_by": [ + { + "manual": True, + "post_devcontainer_start": True, + "post_environment_start": True, + } + ], + }, + spec={ + "commands": { + "ready": "curl -s http://localhost:3000", + "start": "npm run dev", + "stop": "stop", + }, + "desired_phase": "SERVICE_PHASE_UNSPECIFIED", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + "session": "session", + "spec_version": "specVersion", + }, + ) + assert_matches_type(ServiceCreateResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.environments.automations.services.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = response.parse() + assert_matches_type(ServiceCreateResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.environments.automations.services.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = response.parse() + assert_matches_type(ServiceCreateResponse, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + service = client.environments.automations.services.retrieve() + assert_matches_type(ServiceRetrieveResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + service = client.environments.automations.services.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(ServiceRetrieveResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.environments.automations.services.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = response.parse() + assert_matches_type(ServiceRetrieveResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.environments.automations.services.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = response.parse() + assert_matches_type(ServiceRetrieveResponse, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + service = client.environments.automations.services.update() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + service = client.environments.automations.services.update( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + metadata={ + "description": "description", + "name": "x", + "triggered_by": { + "trigger": [ + { + "manual": True, + "post_devcontainer_start": True, + "post_environment_start": True, + } + ] + }, + }, + spec={ + "commands": { + "ready": "curl -s http://localhost:8080", + "start": "npm run start:dev", + "stop": "stop", + }, + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + }, + status={ + "failure_message": "failureMessage", + "log_url": "logUrl", + "output": {"foo": "string"}, + "phase": "SERVICE_PHASE_UNSPECIFIED", + "session": "session", + }, + ) + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.environments.automations.services.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = response.parse() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.environments.automations.services.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = response.parse() + assert_matches_type(object, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + service = client.environments.automations.services.list() + assert_matches_type(SyncServicesPage[Service], service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + service = client.environments.automations.services.list( + token="token", + page_size=0, + filter={ + "environment_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "references": ["web-server", "database"], + "service_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncServicesPage[Service], service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.environments.automations.services.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = response.parse() + assert_matches_type(SyncServicesPage[Service], service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.environments.automations.services.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = response.parse() + assert_matches_type(SyncServicesPage[Service], service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + service = client.environments.automations.services.delete() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + service = client.environments.automations.services.delete( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + force=False, + ) + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.environments.automations.services.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = response.parse() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.environments.automations.services.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = response.parse() + assert_matches_type(object, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_start(self, client: Gitpod) -> None: + service = client.environments.automations.services.start() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_start_with_all_params(self, client: Gitpod) -> None: + service = client.environments.automations.services.start( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_start(self, client: Gitpod) -> None: + response = client.environments.automations.services.with_raw_response.start() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = response.parse() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_start(self, client: Gitpod) -> None: + with client.environments.automations.services.with_streaming_response.start() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = response.parse() + assert_matches_type(object, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_stop(self, client: Gitpod) -> None: + service = client.environments.automations.services.stop() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_stop_with_all_params(self, client: Gitpod) -> None: + service = client.environments.automations.services.stop( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_stop(self, client: Gitpod) -> None: + response = client.environments.automations.services.with_raw_response.stop() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = response.parse() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_stop(self, client: Gitpod) -> None: + with client.environments.automations.services.with_streaming_response.stop() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = response.parse() + assert_matches_type(object, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncServices: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.create() + assert_matches_type(ServiceCreateResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.create( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + metadata={ + "created_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "creator": { + "id": "id", + "principal": "PRINCIPAL_UNSPECIFIED", + }, + "description": "Runs the development web server", + "name": "Web Server", + "reference": "web-server", + "triggered_by": [ + { + "manual": True, + "post_devcontainer_start": True, + "post_environment_start": True, + } + ], + }, + spec={ + "commands": { + "ready": "curl -s http://localhost:3000", + "start": "npm run dev", + "stop": "stop", + }, + "desired_phase": "SERVICE_PHASE_UNSPECIFIED", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + "session": "session", + "spec_version": "specVersion", + }, + ) + assert_matches_type(ServiceCreateResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.services.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = await response.parse() + assert_matches_type(ServiceCreateResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.services.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = await response.parse() + assert_matches_type(ServiceCreateResponse, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.retrieve() + assert_matches_type(ServiceRetrieveResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(ServiceRetrieveResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.services.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = await response.parse() + assert_matches_type(ServiceRetrieveResponse, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.services.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = await response.parse() + assert_matches_type(ServiceRetrieveResponse, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.update() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.update( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + metadata={ + "description": "description", + "name": "x", + "triggered_by": { + "trigger": [ + { + "manual": True, + "post_devcontainer_start": True, + "post_environment_start": True, + } + ] + }, + }, + spec={ + "commands": { + "ready": "curl -s http://localhost:8080", + "start": "npm run start:dev", + "stop": "stop", + }, + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + }, + status={ + "failure_message": "failureMessage", + "log_url": "logUrl", + "output": {"foo": "string"}, + "phase": "SERVICE_PHASE_UNSPECIFIED", + "session": "session", + }, + ) + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.services.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = await response.parse() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.services.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = await response.parse() + assert_matches_type(object, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.list() + assert_matches_type(AsyncServicesPage[Service], service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.list( + token="token", + page_size=0, + filter={ + "environment_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "references": ["web-server", "database"], + "service_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncServicesPage[Service], service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.services.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = await response.parse() + assert_matches_type(AsyncServicesPage[Service], service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.services.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = await response.parse() + assert_matches_type(AsyncServicesPage[Service], service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.delete() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.delete( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + force=False, + ) + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.services.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = await response.parse() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.services.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = await response.parse() + assert_matches_type(object, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_start(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.start() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_start_with_all_params(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.start( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_start(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.services.with_raw_response.start() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = await response.parse() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_start(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.services.with_streaming_response.start() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = await response.parse() + assert_matches_type(object, service, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_stop(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.stop() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_stop_with_all_params(self, async_client: AsyncGitpod) -> None: + service = await async_client.environments.automations.services.stop( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_stop(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.services.with_raw_response.stop() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + service = await response.parse() + assert_matches_type(object, service, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_stop(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.services.with_streaming_response.stop() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + service = await response.parse() + assert_matches_type(object, service, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/environments/automations/test_tasks.py b/tests/api_resources/environments/automations/test_tasks.py new file mode 100644 index 0000000..3d97263 --- /dev/null +++ b/tests/api_resources/environments/automations/test_tasks.py @@ -0,0 +1,583 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod._utils import parse_datetime +from gitpod.pagination import SyncTasksPage, AsyncTasksPage +from gitpod.types.shared import Task +from gitpod.types.environments.automations import ( + TaskStartResponse, + TaskCreateResponse, + TaskRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTasks: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.create() + assert_matches_type(TaskCreateResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.create( + depends_on=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + metadata={ + "created_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "creator": { + "id": "id", + "principal": "PRINCIPAL_UNSPECIFIED", + }, + "description": "Builds the project artifacts", + "name": "Build Project", + "reference": "build", + "triggered_by": [ + { + "manual": True, + "post_devcontainer_start": True, + "post_environment_start": True, + } + ], + }, + spec={ + "command": "npm run build", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + }, + ) + assert_matches_type(TaskCreateResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(TaskCreateResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.environments.automations.tasks.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(TaskCreateResponse, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.retrieve() + assert_matches_type(TaskRetrieveResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(TaskRetrieveResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(TaskRetrieveResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.environments.automations.tasks.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(TaskRetrieveResponse, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.update() + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.update( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + depends_on=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + metadata={ + "description": "description", + "name": "x", + "triggered_by": { + "trigger": [ + { + "manual": True, + "post_devcontainer_start": True, + "post_environment_start": True, + } + ] + }, + }, + spec={ + "command": "npm run test:coverage", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + }, + ) + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.environments.automations.tasks.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(object, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.list() + assert_matches_type(SyncTasksPage[Task], task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.list( + token="token", + page_size=0, + filter={ + "environment_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "references": ["build", "test"], + "task_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncTasksPage[Task], task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(SyncTasksPage[Task], task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.environments.automations.tasks.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(SyncTasksPage[Task], task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.delete() + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.delete( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.environments.automations.tasks.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(object, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_start(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.start() + assert_matches_type(TaskStartResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_start_with_all_params(self, client: Gitpod) -> None: + task = client.environments.automations.tasks.start( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(TaskStartResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_start(self, client: Gitpod) -> None: + response = client.environments.automations.tasks.with_raw_response.start() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(TaskStartResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_start(self, client: Gitpod) -> None: + with client.environments.automations.tasks.with_streaming_response.start() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(TaskStartResponse, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncTasks: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.create() + assert_matches_type(TaskCreateResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.create( + depends_on=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + metadata={ + "created_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "creator": { + "id": "id", + "principal": "PRINCIPAL_UNSPECIFIED", + }, + "description": "Builds the project artifacts", + "name": "Build Project", + "reference": "build", + "triggered_by": [ + { + "manual": True, + "post_devcontainer_start": True, + "post_environment_start": True, + } + ], + }, + spec={ + "command": "npm run build", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + }, + ) + assert_matches_type(TaskCreateResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(TaskCreateResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.tasks.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(TaskCreateResponse, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.retrieve() + assert_matches_type(TaskRetrieveResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(TaskRetrieveResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(TaskRetrieveResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.tasks.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(TaskRetrieveResponse, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.update() + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.update( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + depends_on=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + metadata={ + "description": "description", + "name": "x", + "triggered_by": { + "trigger": [ + { + "manual": True, + "post_devcontainer_start": True, + "post_environment_start": True, + } + ] + }, + }, + spec={ + "command": "npm run test:coverage", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + }, + ) + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.tasks.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(object, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.list() + assert_matches_type(AsyncTasksPage[Task], task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.list( + token="token", + page_size=0, + filter={ + "environment_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "references": ["build", "test"], + "task_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncTasksPage[Task], task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(AsyncTasksPage[Task], task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.tasks.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(AsyncTasksPage[Task], task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.delete() + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.delete( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(object, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.tasks.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(object, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_start(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.start() + assert_matches_type(TaskStartResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_start_with_all_params(self, async_client: AsyncGitpod) -> None: + task = await async_client.environments.automations.tasks.start( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(TaskStartResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_start(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.tasks.with_raw_response.start() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(TaskStartResponse, task, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_start(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.tasks.with_streaming_response.start() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(TaskStartResponse, task, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/environments/test_automations.py b/tests/api_resources/environments/test_automations.py new file mode 100644 index 0000000..40362d6 --- /dev/null +++ b/tests/api_resources/environments/test_automations.py @@ -0,0 +1,166 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types.environments import AutomationUpsertResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAutomations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_upsert(self, client: Gitpod) -> None: + automation = client.environments.automations.upsert() + assert_matches_type(AutomationUpsertResponse, automation, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_upsert_with_all_params(self, client: Gitpod) -> None: + automation = client.environments.automations.upsert( + automations_file={ + "services": { + "web-server": { + "commands": { + "ready": "curl -s http://localhost:3000", + "start": "npm run dev", + "stop": "stop", + }, + "description": "Development web server", + "name": "Web Server", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + "triggered_by": ["postDevcontainerStart"], + } + }, + "tasks": { + "build": { + "command": "npm run build", + "depends_on": ["string"], + "description": "Builds the project artifacts", + "name": "Build Project", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + "triggered_by": ["postEnvironmentStart"], + } + }, + }, + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(AutomationUpsertResponse, automation, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_upsert(self, client: Gitpod) -> None: + response = client.environments.automations.with_raw_response.upsert() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + automation = response.parse() + assert_matches_type(AutomationUpsertResponse, automation, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_upsert(self, client: Gitpod) -> None: + with client.environments.automations.with_streaming_response.upsert() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + automation = response.parse() + assert_matches_type(AutomationUpsertResponse, automation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAutomations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_upsert(self, async_client: AsyncGitpod) -> None: + automation = await async_client.environments.automations.upsert() + assert_matches_type(AutomationUpsertResponse, automation, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_upsert_with_all_params(self, async_client: AsyncGitpod) -> None: + automation = await async_client.environments.automations.upsert( + automations_file={ + "services": { + "web-server": { + "commands": { + "ready": "curl -s http://localhost:3000", + "start": "npm run dev", + "stop": "stop", + }, + "description": "Development web server", + "name": "Web Server", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + "triggered_by": ["postDevcontainerStart"], + } + }, + "tasks": { + "build": { + "command": "npm run build", + "depends_on": ["string"], + "description": "Builds the project artifacts", + "name": "Build Project", + "runs_on": { + "docker": { + "environment": ["string"], + "image": "x", + } + }, + "triggered_by": ["postEnvironmentStart"], + } + }, + }, + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(AutomationUpsertResponse, automation, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_upsert(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.automations.with_raw_response.upsert() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + automation = await response.parse() + assert_matches_type(AutomationUpsertResponse, automation, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_upsert(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.automations.with_streaming_response.upsert() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + automation = await response.parse() + assert_matches_type(AutomationUpsertResponse, automation, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/environments/test_classes.py b/tests/api_resources/environments/test_classes.py new file mode 100644 index 0000000..3049c13 --- /dev/null +++ b/tests/api_resources/environments/test_classes.py @@ -0,0 +1,121 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncEnvironmentClassesPage, AsyncEnvironmentClassesPage +from gitpod.types.shared import EnvironmentClass + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestClasses: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + class_ = client.environments.classes.list() + assert_matches_type(SyncEnvironmentClassesPage[EnvironmentClass], class_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + class_ = client.environments.classes.list( + token="token", + page_size=0, + filter={ + "can_create_environments": True, + "enabled": True, + "runner_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "runner_kinds": ["RUNNER_KIND_UNSPECIFIED"], + "runner_providers": ["RUNNER_PROVIDER_UNSPECIFIED"], + }, + pagination={ + "token": "token", + "page_size": 100, + }, + ) + assert_matches_type(SyncEnvironmentClassesPage[EnvironmentClass], class_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.environments.classes.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + class_ = response.parse() + assert_matches_type(SyncEnvironmentClassesPage[EnvironmentClass], class_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.environments.classes.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + class_ = response.parse() + assert_matches_type(SyncEnvironmentClassesPage[EnvironmentClass], class_, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncClasses: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + class_ = await async_client.environments.classes.list() + assert_matches_type(AsyncEnvironmentClassesPage[EnvironmentClass], class_, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + class_ = await async_client.environments.classes.list( + token="token", + page_size=0, + filter={ + "can_create_environments": True, + "enabled": True, + "runner_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "runner_kinds": ["RUNNER_KIND_UNSPECIFIED"], + "runner_providers": ["RUNNER_PROVIDER_UNSPECIFIED"], + }, + pagination={ + "token": "token", + "page_size": 100, + }, + ) + assert_matches_type(AsyncEnvironmentClassesPage[EnvironmentClass], class_, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.classes.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + class_ = await response.parse() + assert_matches_type(AsyncEnvironmentClassesPage[EnvironmentClass], class_, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.classes.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + class_ = await response.parse() + assert_matches_type(AsyncEnvironmentClassesPage[EnvironmentClass], class_, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/organizations/__init__.py b/tests/api_resources/organizations/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/organizations/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/organizations/test_domain_verifications.py b/tests/api_resources/organizations/test_domain_verifications.py new file mode 100644 index 0000000..b9e06da --- /dev/null +++ b/tests/api_resources/organizations/test_domain_verifications.py @@ -0,0 +1,406 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncDomainVerificationsPage, AsyncDomainVerificationsPage +from gitpod.types.organizations import ( + DomainVerification, + DomainVerificationCreateResponse, + DomainVerificationVerifyResponse, + DomainVerificationRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDomainVerifications: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + domain_verification = client.organizations.domain_verifications.create( + domain="acme-corp.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(DomainVerificationCreateResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.organizations.domain_verifications.with_raw_response.create( + domain="acme-corp.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = response.parse() + assert_matches_type(DomainVerificationCreateResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.organizations.domain_verifications.with_streaming_response.create( + domain="acme-corp.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = response.parse() + assert_matches_type(DomainVerificationCreateResponse, domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + domain_verification = client.organizations.domain_verifications.retrieve( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(DomainVerificationRetrieveResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.organizations.domain_verifications.with_raw_response.retrieve( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = response.parse() + assert_matches_type(DomainVerificationRetrieveResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.organizations.domain_verifications.with_streaming_response.retrieve( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = response.parse() + assert_matches_type(DomainVerificationRetrieveResponse, domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + domain_verification = client.organizations.domain_verifications.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(SyncDomainVerificationsPage[DomainVerification], domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + domain_verification = client.organizations.domain_verifications.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncDomainVerificationsPage[DomainVerification], domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.organizations.domain_verifications.with_raw_response.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = response.parse() + assert_matches_type(SyncDomainVerificationsPage[DomainVerification], domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.organizations.domain_verifications.with_streaming_response.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = response.parse() + assert_matches_type(SyncDomainVerificationsPage[DomainVerification], domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + domain_verification = client.organizations.domain_verifications.delete( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.organizations.domain_verifications.with_raw_response.delete( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = response.parse() + assert_matches_type(object, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.organizations.domain_verifications.with_streaming_response.delete( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = response.parse() + assert_matches_type(object, domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_verify(self, client: Gitpod) -> None: + domain_verification = client.organizations.domain_verifications.verify( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(DomainVerificationVerifyResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_verify(self, client: Gitpod) -> None: + response = client.organizations.domain_verifications.with_raw_response.verify( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = response.parse() + assert_matches_type(DomainVerificationVerifyResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_verify(self, client: Gitpod) -> None: + with client.organizations.domain_verifications.with_streaming_response.verify( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = response.parse() + assert_matches_type(DomainVerificationVerifyResponse, domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncDomainVerifications: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + domain_verification = await async_client.organizations.domain_verifications.create( + domain="acme-corp.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(DomainVerificationCreateResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.domain_verifications.with_raw_response.create( + domain="acme-corp.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = await response.parse() + assert_matches_type(DomainVerificationCreateResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.domain_verifications.with_streaming_response.create( + domain="acme-corp.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = await response.parse() + assert_matches_type(DomainVerificationCreateResponse, domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + domain_verification = await async_client.organizations.domain_verifications.retrieve( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(DomainVerificationRetrieveResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.domain_verifications.with_raw_response.retrieve( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = await response.parse() + assert_matches_type(DomainVerificationRetrieveResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.domain_verifications.with_streaming_response.retrieve( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = await response.parse() + assert_matches_type(DomainVerificationRetrieveResponse, domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + domain_verification = await async_client.organizations.domain_verifications.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(AsyncDomainVerificationsPage[DomainVerification], domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + domain_verification = await async_client.organizations.domain_verifications.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncDomainVerificationsPage[DomainVerification], domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.domain_verifications.with_raw_response.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = await response.parse() + assert_matches_type(AsyncDomainVerificationsPage[DomainVerification], domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.domain_verifications.with_streaming_response.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = await response.parse() + assert_matches_type( + AsyncDomainVerificationsPage[DomainVerification], domain_verification, path=["response"] + ) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + domain_verification = await async_client.organizations.domain_verifications.delete( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.domain_verifications.with_raw_response.delete( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = await response.parse() + assert_matches_type(object, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.domain_verifications.with_streaming_response.delete( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = await response.parse() + assert_matches_type(object, domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_verify(self, async_client: AsyncGitpod) -> None: + domain_verification = await async_client.organizations.domain_verifications.verify( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(DomainVerificationVerifyResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_verify(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.domain_verifications.with_raw_response.verify( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain_verification = await response.parse() + assert_matches_type(DomainVerificationVerifyResponse, domain_verification, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_verify(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.domain_verifications.with_streaming_response.verify( + domain_verification_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain_verification = await response.parse() + assert_matches_type(DomainVerificationVerifyResponse, domain_verification, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/organizations/test_invites.py b/tests/api_resources/organizations/test_invites.py new file mode 100644 index 0000000..d1cc059 --- /dev/null +++ b/tests/api_resources/organizations/test_invites.py @@ -0,0 +1,232 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types.organizations import ( + InviteCreateResponse, + InviteRetrieveResponse, + InviteGetSummaryResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInvites: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + invite = client.organizations.invites.create( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(InviteCreateResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.organizations.invites.with_raw_response.create( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(InviteCreateResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.organizations.invites.with_streaming_response.create( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = response.parse() + assert_matches_type(InviteCreateResponse, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + invite = client.organizations.invites.retrieve( + organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(InviteRetrieveResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.organizations.invites.with_raw_response.retrieve( + organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(InviteRetrieveResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.organizations.invites.with_streaming_response.retrieve( + organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = response.parse() + assert_matches_type(InviteRetrieveResponse, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_get_summary(self, client: Gitpod) -> None: + invite = client.organizations.invites.get_summary( + invite_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(InviteGetSummaryResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_get_summary(self, client: Gitpod) -> None: + response = client.organizations.invites.with_raw_response.get_summary( + invite_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = response.parse() + assert_matches_type(InviteGetSummaryResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_get_summary(self, client: Gitpod) -> None: + with client.organizations.invites.with_streaming_response.get_summary( + invite_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = response.parse() + assert_matches_type(InviteGetSummaryResponse, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncInvites: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + invite = await async_client.organizations.invites.create( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(InviteCreateResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.invites.with_raw_response.create( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = await response.parse() + assert_matches_type(InviteCreateResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.invites.with_streaming_response.create( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = await response.parse() + assert_matches_type(InviteCreateResponse, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + invite = await async_client.organizations.invites.retrieve( + organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(InviteRetrieveResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.invites.with_raw_response.retrieve( + organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = await response.parse() + assert_matches_type(InviteRetrieveResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.invites.with_streaming_response.retrieve( + organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = await response.parse() + assert_matches_type(InviteRetrieveResponse, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_get_summary(self, async_client: AsyncGitpod) -> None: + invite = await async_client.organizations.invites.get_summary( + invite_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(InviteGetSummaryResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_get_summary(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.invites.with_raw_response.get_summary( + invite_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invite = await response.parse() + assert_matches_type(InviteGetSummaryResponse, invite, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_get_summary(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.invites.with_streaming_response.get_summary( + invite_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invite = await response.parse() + assert_matches_type(InviteGetSummaryResponse, invite, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/organizations/test_policies.py b/tests/api_resources/organizations/test_policies.py new file mode 100644 index 0000000..b539b9c --- /dev/null +++ b/tests/api_resources/organizations/test_policies.py @@ -0,0 +1,196 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types.organizations import PolicyRetrieveResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPolicies: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + policy = client.organizations.policies.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(PolicyRetrieveResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.organizations.policies.with_raw_response.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(PolicyRetrieveResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.organizations.policies.with_streaming_response.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(PolicyRetrieveResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + policy = client.organizations.policies.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + policy = client.organizations.policies.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + allowed_editor_ids=["string"], + allow_local_runners=True, + default_editor_id="defaultEditorId", + default_environment_image="defaultEnvironmentImage", + maximum_environments_per_user="20", + maximum_environment_timeout="3600s", + maximum_running_environments_per_user="5", + members_create_projects=True, + members_require_projects=True, + port_sharing_disabled=True, + ) + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.organizations.policies.with_raw_response.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.organizations.policies.with_streaming_response.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(object, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPolicies: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + policy = await async_client.organizations.policies.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(PolicyRetrieveResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.policies.with_raw_response.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(PolicyRetrieveResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.policies.with_streaming_response.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(PolicyRetrieveResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + policy = await async_client.organizations.policies.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.organizations.policies.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + allowed_editor_ids=["string"], + allow_local_runners=True, + default_editor_id="defaultEditorId", + default_environment_image="defaultEnvironmentImage", + maximum_environments_per_user="20", + maximum_environment_timeout="3600s", + maximum_running_environments_per_user="5", + members_create_projects=True, + members_require_projects=True, + port_sharing_disabled=True, + ) + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.policies.with_raw_response.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.policies.with_streaming_response.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(object, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/organizations/test_sso_configurations.py b/tests/api_resources/organizations/test_sso_configurations.py new file mode 100644 index 0000000..deba284 --- /dev/null +++ b/tests/api_resources/organizations/test_sso_configurations.py @@ -0,0 +1,449 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncSSOConfigurationsPage, AsyncSSOConfigurationsPage +from gitpod.types.organizations import ( + SSOConfiguration, + SSOConfigurationCreateResponse, + SSOConfigurationRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSSOConfigurations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + sso_configuration = client.organizations.sso_configurations.create( + client_id="012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com", + client_secret="GOCSPX-abcdefghijklmnopqrstuvwxyz123456", + email_domain="acme-corp.com", + issuer_url="https://accounts.google.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(SSOConfigurationCreateResponse, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.organizations.sso_configurations.with_raw_response.create( + client_id="012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com", + client_secret="GOCSPX-abcdefghijklmnopqrstuvwxyz123456", + email_domain="acme-corp.com", + issuer_url="https://accounts.google.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = response.parse() + assert_matches_type(SSOConfigurationCreateResponse, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.organizations.sso_configurations.with_streaming_response.create( + client_id="012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com", + client_secret="GOCSPX-abcdefghijklmnopqrstuvwxyz123456", + email_domain="acme-corp.com", + issuer_url="https://accounts.google.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = response.parse() + assert_matches_type(SSOConfigurationCreateResponse, sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + sso_configuration = client.organizations.sso_configurations.retrieve( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(SSOConfigurationRetrieveResponse, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.organizations.sso_configurations.with_raw_response.retrieve( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = response.parse() + assert_matches_type(SSOConfigurationRetrieveResponse, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.organizations.sso_configurations.with_streaming_response.retrieve( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = response.parse() + assert_matches_type(SSOConfigurationRetrieveResponse, sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + sso_configuration = client.organizations.sso_configurations.update( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + sso_configuration = client.organizations.sso_configurations.update( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + claims={"foo": "string"}, + client_id="new-client-id", + client_secret="new-client-secret", + email_domain="xxxx", + issuer_url="https://example.com", + state="SSO_CONFIGURATION_STATE_UNSPECIFIED", + ) + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.organizations.sso_configurations.with_raw_response.update( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = response.parse() + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.organizations.sso_configurations.with_streaming_response.update( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = response.parse() + assert_matches_type(object, sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + sso_configuration = client.organizations.sso_configurations.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(SyncSSOConfigurationsPage[SSOConfiguration], sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + sso_configuration = client.organizations.sso_configurations.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncSSOConfigurationsPage[SSOConfiguration], sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.organizations.sso_configurations.with_raw_response.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = response.parse() + assert_matches_type(SyncSSOConfigurationsPage[SSOConfiguration], sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.organizations.sso_configurations.with_streaming_response.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = response.parse() + assert_matches_type(SyncSSOConfigurationsPage[SSOConfiguration], sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + sso_configuration = client.organizations.sso_configurations.delete( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.organizations.sso_configurations.with_raw_response.delete( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = response.parse() + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.organizations.sso_configurations.with_streaming_response.delete( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = response.parse() + assert_matches_type(object, sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncSSOConfigurations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + sso_configuration = await async_client.organizations.sso_configurations.create( + client_id="012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com", + client_secret="GOCSPX-abcdefghijklmnopqrstuvwxyz123456", + email_domain="acme-corp.com", + issuer_url="https://accounts.google.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(SSOConfigurationCreateResponse, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.sso_configurations.with_raw_response.create( + client_id="012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com", + client_secret="GOCSPX-abcdefghijklmnopqrstuvwxyz123456", + email_domain="acme-corp.com", + issuer_url="https://accounts.google.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = await response.parse() + assert_matches_type(SSOConfigurationCreateResponse, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.sso_configurations.with_streaming_response.create( + client_id="012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com", + client_secret="GOCSPX-abcdefghijklmnopqrstuvwxyz123456", + email_domain="acme-corp.com", + issuer_url="https://accounts.google.com", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = await response.parse() + assert_matches_type(SSOConfigurationCreateResponse, sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + sso_configuration = await async_client.organizations.sso_configurations.retrieve( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(SSOConfigurationRetrieveResponse, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.sso_configurations.with_raw_response.retrieve( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = await response.parse() + assert_matches_type(SSOConfigurationRetrieveResponse, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.sso_configurations.with_streaming_response.retrieve( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = await response.parse() + assert_matches_type(SSOConfigurationRetrieveResponse, sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + sso_configuration = await async_client.organizations.sso_configurations.update( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + sso_configuration = await async_client.organizations.sso_configurations.update( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + claims={"foo": "string"}, + client_id="new-client-id", + client_secret="new-client-secret", + email_domain="xxxx", + issuer_url="https://example.com", + state="SSO_CONFIGURATION_STATE_UNSPECIFIED", + ) + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.sso_configurations.with_raw_response.update( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = await response.parse() + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.sso_configurations.with_streaming_response.update( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = await response.parse() + assert_matches_type(object, sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + sso_configuration = await async_client.organizations.sso_configurations.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(AsyncSSOConfigurationsPage[SSOConfiguration], sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + sso_configuration = await async_client.organizations.sso_configurations.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncSSOConfigurationsPage[SSOConfiguration], sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.sso_configurations.with_raw_response.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = await response.parse() + assert_matches_type(AsyncSSOConfigurationsPage[SSOConfiguration], sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.sso_configurations.with_streaming_response.list( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = await response.parse() + assert_matches_type(AsyncSSOConfigurationsPage[SSOConfiguration], sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + sso_configuration = await async_client.organizations.sso_configurations.delete( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.sso_configurations.with_raw_response.delete( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sso_configuration = await response.parse() + assert_matches_type(object, sso_configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.sso_configurations.with_streaming_response.delete( + sso_configuration_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sso_configuration = await response.parse() + assert_matches_type(object, sso_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/projects/__init__.py b/tests/api_resources/projects/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/projects/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/projects/test_policies.py b/tests/api_resources/projects/test_policies.py new file mode 100644 index 0000000..430b982 --- /dev/null +++ b/tests/api_resources/projects/test_policies.py @@ -0,0 +1,339 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncPoliciesPage, AsyncPoliciesPage +from gitpod.types.projects import ( + ProjectPolicy, + PolicyCreateResponse, + PolicyUpdateResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPolicies: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + policy = client.projects.policies.create() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + policy = client.projects.policies.create( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + role="PROJECT_ROLE_ADMIN", + ) + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.projects.policies.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.projects.policies.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + policy = client.projects.policies.update() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + policy = client.projects.policies.update( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + role="PROJECT_ROLE_EDITOR", + ) + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.projects.policies.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.projects.policies.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + policy = client.projects.policies.list() + assert_matches_type(SyncPoliciesPage[ProjectPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + policy = client.projects.policies.list( + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(SyncPoliciesPage[ProjectPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.projects.policies.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(SyncPoliciesPage[ProjectPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.projects.policies.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(SyncPoliciesPage[ProjectPolicy], policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + policy = client.projects.policies.delete() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + policy = client.projects.policies.delete( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.projects.policies.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.projects.policies.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(object, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPolicies: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + policy = await async_client.projects.policies.create() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.projects.policies.create( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + role="PROJECT_ROLE_ADMIN", + ) + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.policies.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.policies.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + policy = await async_client.projects.policies.update() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.projects.policies.update( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + role="PROJECT_ROLE_EDITOR", + ) + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.policies.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.policies.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + policy = await async_client.projects.policies.list() + assert_matches_type(AsyncPoliciesPage[ProjectPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.projects.policies.list( + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(AsyncPoliciesPage[ProjectPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.policies.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(AsyncPoliciesPage[ProjectPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.policies.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(AsyncPoliciesPage[ProjectPolicy], policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + policy = await async_client.projects.policies.delete() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.projects.policies.delete( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.policies.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.policies.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(object, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/runners/__init__.py b/tests/api_resources/runners/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/runners/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/runners/configurations/__init__.py b/tests/api_resources/runners/configurations/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/runners/configurations/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/runners/configurations/test_environment_classes.py b/tests/api_resources/runners/configurations/test_environment_classes.py new file mode 100644 index 0000000..649e807 --- /dev/null +++ b/tests/api_resources/runners/configurations/test_environment_classes.py @@ -0,0 +1,373 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncEnvironmentClassesPage, AsyncEnvironmentClassesPage +from gitpod.types.shared import EnvironmentClass +from gitpod.types.runners.configurations import ( + EnvironmentClassCreateResponse, + EnvironmentClassRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestEnvironmentClasses: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + environment_class = client.runners.configurations.environment_classes.create() + assert_matches_type(EnvironmentClassCreateResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + environment_class = client.runners.configurations.environment_classes.create( + configuration=[ + { + "key": "cpu", + "value": "8", + }, + { + "key": "memory", + "value": "16384", + }, + ], + description="8 CPU, 16GB RAM", + display_name="Large Instance", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(EnvironmentClassCreateResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.runners.configurations.environment_classes.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment_class = response.parse() + assert_matches_type(EnvironmentClassCreateResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.runners.configurations.environment_classes.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment_class = response.parse() + assert_matches_type(EnvironmentClassCreateResponse, environment_class, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + environment_class = client.runners.configurations.environment_classes.retrieve() + assert_matches_type(EnvironmentClassRetrieveResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + environment_class = client.runners.configurations.environment_classes.retrieve( + environment_class_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(EnvironmentClassRetrieveResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.runners.configurations.environment_classes.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment_class = response.parse() + assert_matches_type(EnvironmentClassRetrieveResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.runners.configurations.environment_classes.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment_class = response.parse() + assert_matches_type(EnvironmentClassRetrieveResponse, environment_class, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + environment_class = client.runners.configurations.environment_classes.update() + assert_matches_type(object, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + environment_class = client.runners.configurations.environment_classes.update( + description="16 CPU, 32GB RAM", + display_name="Updated Large Instance", + enabled=True, + environment_class_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.runners.configurations.environment_classes.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment_class = response.parse() + assert_matches_type(object, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.runners.configurations.environment_classes.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment_class = response.parse() + assert_matches_type(object, environment_class, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + environment_class = client.runners.configurations.environment_classes.list() + assert_matches_type(SyncEnvironmentClassesPage[EnvironmentClass], environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + environment_class = client.runners.configurations.environment_classes.list( + token="token", + page_size=0, + filter={ + "can_create_environments": True, + "enabled": True, + "runner_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "runner_kinds": ["RUNNER_KIND_UNSPECIFIED"], + "runner_providers": ["RUNNER_PROVIDER_UNSPECIFIED"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncEnvironmentClassesPage[EnvironmentClass], environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.runners.configurations.environment_classes.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment_class = response.parse() + assert_matches_type(SyncEnvironmentClassesPage[EnvironmentClass], environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.runners.configurations.environment_classes.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment_class = response.parse() + assert_matches_type(SyncEnvironmentClassesPage[EnvironmentClass], environment_class, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncEnvironmentClasses: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + environment_class = await async_client.runners.configurations.environment_classes.create() + assert_matches_type(EnvironmentClassCreateResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + environment_class = await async_client.runners.configurations.environment_classes.create( + configuration=[ + { + "key": "cpu", + "value": "8", + }, + { + "key": "memory", + "value": "16384", + }, + ], + description="8 CPU, 16GB RAM", + display_name="Large Instance", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(EnvironmentClassCreateResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.environment_classes.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment_class = await response.parse() + assert_matches_type(EnvironmentClassCreateResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.environment_classes.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment_class = await response.parse() + assert_matches_type(EnvironmentClassCreateResponse, environment_class, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + environment_class = await async_client.runners.configurations.environment_classes.retrieve() + assert_matches_type(EnvironmentClassRetrieveResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + environment_class = await async_client.runners.configurations.environment_classes.retrieve( + environment_class_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(EnvironmentClassRetrieveResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.environment_classes.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment_class = await response.parse() + assert_matches_type(EnvironmentClassRetrieveResponse, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with ( + async_client.runners.configurations.environment_classes.with_streaming_response.retrieve() + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment_class = await response.parse() + assert_matches_type(EnvironmentClassRetrieveResponse, environment_class, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + environment_class = await async_client.runners.configurations.environment_classes.update() + assert_matches_type(object, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + environment_class = await async_client.runners.configurations.environment_classes.update( + description="16 CPU, 32GB RAM", + display_name="Updated Large Instance", + enabled=True, + environment_class_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.environment_classes.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment_class = await response.parse() + assert_matches_type(object, environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.environment_classes.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment_class = await response.parse() + assert_matches_type(object, environment_class, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + environment_class = await async_client.runners.configurations.environment_classes.list() + assert_matches_type(AsyncEnvironmentClassesPage[EnvironmentClass], environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + environment_class = await async_client.runners.configurations.environment_classes.list( + token="token", + page_size=0, + filter={ + "can_create_environments": True, + "enabled": True, + "runner_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "runner_kinds": ["RUNNER_KIND_UNSPECIFIED"], + "runner_providers": ["RUNNER_PROVIDER_UNSPECIFIED"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncEnvironmentClassesPage[EnvironmentClass], environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.environment_classes.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment_class = await response.parse() + assert_matches_type(AsyncEnvironmentClassesPage[EnvironmentClass], environment_class, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.environment_classes.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment_class = await response.parse() + assert_matches_type(AsyncEnvironmentClassesPage[EnvironmentClass], environment_class, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/runners/configurations/test_host_authentication_tokens.py b/tests/api_resources/runners/configurations/test_host_authentication_tokens.py new file mode 100644 index 0000000..0766e3a --- /dev/null +++ b/tests/api_resources/runners/configurations/test_host_authentication_tokens.py @@ -0,0 +1,436 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod._utils import parse_datetime +from gitpod.pagination import SyncTokensPage, AsyncTokensPage +from gitpod.types.runners.configurations import ( + HostAuthenticationToken, + HostAuthenticationTokenCreateResponse, + HostAuthenticationTokenRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestHostAuthenticationTokens: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.create() + assert_matches_type(HostAuthenticationTokenCreateResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.create( + token="gho_xxxxxxxxxxxx", + expires_at=parse_datetime("2024-12-31T23:59:59Z"), + host="github.com", + refresh_token="ghr_xxxxxxxxxxxx", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + source="HOST_AUTHENTICATION_TOKEN_SOURCE_OAUTH", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(HostAuthenticationTokenCreateResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.runners.configurations.host_authentication_tokens.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = response.parse() + assert_matches_type(HostAuthenticationTokenCreateResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.runners.configurations.host_authentication_tokens.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = response.parse() + assert_matches_type(HostAuthenticationTokenCreateResponse, host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.retrieve() + assert_matches_type(HostAuthenticationTokenRetrieveResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(HostAuthenticationTokenRetrieveResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.runners.configurations.host_authentication_tokens.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = response.parse() + assert_matches_type(HostAuthenticationTokenRetrieveResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.runners.configurations.host_authentication_tokens.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = response.parse() + assert_matches_type(HostAuthenticationTokenRetrieveResponse, host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.update() + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.update( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + token="gho_xxxxxxxxxxxx", + expires_at=parse_datetime("2024-12-31T23:59:59Z"), + refresh_token="ghr_xxxxxxxxxxxx", + ) + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.runners.configurations.host_authentication_tokens.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = response.parse() + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.runners.configurations.host_authentication_tokens.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = response.parse() + assert_matches_type(object, host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.list() + assert_matches_type(SyncTokensPage[HostAuthenticationToken], host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.list( + token="token", + page_size=0, + filter={ + "runner_id": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncTokensPage[HostAuthenticationToken], host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.runners.configurations.host_authentication_tokens.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = response.parse() + assert_matches_type(SyncTokensPage[HostAuthenticationToken], host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.runners.configurations.host_authentication_tokens.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = response.parse() + assert_matches_type(SyncTokensPage[HostAuthenticationToken], host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.delete() + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + host_authentication_token = client.runners.configurations.host_authentication_tokens.delete( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.runners.configurations.host_authentication_tokens.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = response.parse() + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.runners.configurations.host_authentication_tokens.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = response.parse() + assert_matches_type(object, host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncHostAuthenticationTokens: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.create() + assert_matches_type(HostAuthenticationTokenCreateResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.create( + token="gho_xxxxxxxxxxxx", + expires_at=parse_datetime("2024-12-31T23:59:59Z"), + host="github.com", + refresh_token="ghr_xxxxxxxxxxxx", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + source="HOST_AUTHENTICATION_TOKEN_SOURCE_OAUTH", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(HostAuthenticationTokenCreateResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.host_authentication_tokens.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = await response.parse() + assert_matches_type(HostAuthenticationTokenCreateResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with ( + async_client.runners.configurations.host_authentication_tokens.with_streaming_response.create() + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = await response.parse() + assert_matches_type(HostAuthenticationTokenCreateResponse, host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.retrieve() + assert_matches_type(HostAuthenticationTokenRetrieveResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(HostAuthenticationTokenRetrieveResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.host_authentication_tokens.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = await response.parse() + assert_matches_type(HostAuthenticationTokenRetrieveResponse, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with ( + async_client.runners.configurations.host_authentication_tokens.with_streaming_response.retrieve() + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = await response.parse() + assert_matches_type(HostAuthenticationTokenRetrieveResponse, host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.update() + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.update( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + token="gho_xxxxxxxxxxxx", + expires_at=parse_datetime("2024-12-31T23:59:59Z"), + refresh_token="ghr_xxxxxxxxxxxx", + ) + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.host_authentication_tokens.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = await response.parse() + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with ( + async_client.runners.configurations.host_authentication_tokens.with_streaming_response.update() + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = await response.parse() + assert_matches_type(object, host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.list() + assert_matches_type(AsyncTokensPage[HostAuthenticationToken], host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.list( + token="token", + page_size=0, + filter={ + "runner_id": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncTokensPage[HostAuthenticationToken], host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.host_authentication_tokens.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = await response.parse() + assert_matches_type(AsyncTokensPage[HostAuthenticationToken], host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with ( + async_client.runners.configurations.host_authentication_tokens.with_streaming_response.list() + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = await response.parse() + assert_matches_type(AsyncTokensPage[HostAuthenticationToken], host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.delete() + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + host_authentication_token = await async_client.runners.configurations.host_authentication_tokens.delete( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.host_authentication_tokens.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + host_authentication_token = await response.parse() + assert_matches_type(object, host_authentication_token, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with ( + async_client.runners.configurations.host_authentication_tokens.with_streaming_response.delete() + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + host_authentication_token = await response.parse() + assert_matches_type(object, host_authentication_token, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/runners/configurations/test_schema.py b/tests/api_resources/runners/configurations/test_schema.py new file mode 100644 index 0000000..828522f --- /dev/null +++ b/tests/api_resources/runners/configurations/test_schema.py @@ -0,0 +1,96 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types.runners.configurations import SchemaRetrieveResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSchema: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + schema = client.runners.configurations.schema.retrieve() + assert_matches_type(SchemaRetrieveResponse, schema, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + schema = client.runners.configurations.schema.retrieve( + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(SchemaRetrieveResponse, schema, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.runners.configurations.schema.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + schema = response.parse() + assert_matches_type(SchemaRetrieveResponse, schema, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.runners.configurations.schema.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + schema = response.parse() + assert_matches_type(SchemaRetrieveResponse, schema, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncSchema: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + schema = await async_client.runners.configurations.schema.retrieve() + assert_matches_type(SchemaRetrieveResponse, schema, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + schema = await async_client.runners.configurations.schema.retrieve( + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(SchemaRetrieveResponse, schema, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.schema.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + schema = await response.parse() + assert_matches_type(SchemaRetrieveResponse, schema, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.schema.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + schema = await response.parse() + assert_matches_type(SchemaRetrieveResponse, schema, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/runners/configurations/test_scm_integrations.py b/tests/api_resources/runners/configurations/test_scm_integrations.py new file mode 100644 index 0000000..d3c0790 --- /dev/null +++ b/tests/api_resources/runners/configurations/test_scm_integrations.py @@ -0,0 +1,421 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncIntegrationsPage, AsyncIntegrationsPage +from gitpod.types.runners.configurations import ( + ScmIntegration, + ScmIntegrationCreateResponse, + ScmIntegrationRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestScmIntegrations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.create() + assert_matches_type(ScmIntegrationCreateResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.create( + host="github.com", + issuer_url="issuerUrl", + oauth_client_id="client_id", + oauth_plaintext_client_secret="client_secret", + pat=True, + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + scm_id="github", + ) + assert_matches_type(ScmIntegrationCreateResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.runners.configurations.scm_integrations.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = response.parse() + assert_matches_type(ScmIntegrationCreateResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.runners.configurations.scm_integrations.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = response.parse() + assert_matches_type(ScmIntegrationCreateResponse, scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.retrieve() + assert_matches_type(ScmIntegrationRetrieveResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(ScmIntegrationRetrieveResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.runners.configurations.scm_integrations.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = response.parse() + assert_matches_type(ScmIntegrationRetrieveResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.runners.configurations.scm_integrations.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = response.parse() + assert_matches_type(ScmIntegrationRetrieveResponse, scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.update() + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.update( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + issuer_url="issuerUrl", + oauth_client_id="new_client_id", + oauth_plaintext_client_secret="new_client_secret", + pat=True, + ) + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.runners.configurations.scm_integrations.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = response.parse() + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.runners.configurations.scm_integrations.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = response.parse() + assert_matches_type(object, scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.list() + assert_matches_type(SyncIntegrationsPage[ScmIntegration], scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.list( + token="token", + page_size=0, + filter={"runner_ids": ["d2c94c27-3b76-4a42-b88c-95a85e392c68"]}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncIntegrationsPage[ScmIntegration], scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.runners.configurations.scm_integrations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = response.parse() + assert_matches_type(SyncIntegrationsPage[ScmIntegration], scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.runners.configurations.scm_integrations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = response.parse() + assert_matches_type(SyncIntegrationsPage[ScmIntegration], scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.delete() + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + scm_integration = client.runners.configurations.scm_integrations.delete( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.runners.configurations.scm_integrations.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = response.parse() + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.runners.configurations.scm_integrations.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = response.parse() + assert_matches_type(object, scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncScmIntegrations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.create() + assert_matches_type(ScmIntegrationCreateResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.create( + host="github.com", + issuer_url="issuerUrl", + oauth_client_id="client_id", + oauth_plaintext_client_secret="client_secret", + pat=True, + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + scm_id="github", + ) + assert_matches_type(ScmIntegrationCreateResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.scm_integrations.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = await response.parse() + assert_matches_type(ScmIntegrationCreateResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.scm_integrations.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = await response.parse() + assert_matches_type(ScmIntegrationCreateResponse, scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.retrieve() + assert_matches_type(ScmIntegrationRetrieveResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(ScmIntegrationRetrieveResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.scm_integrations.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = await response.parse() + assert_matches_type(ScmIntegrationRetrieveResponse, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.scm_integrations.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = await response.parse() + assert_matches_type(ScmIntegrationRetrieveResponse, scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.update() + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.update( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + issuer_url="issuerUrl", + oauth_client_id="new_client_id", + oauth_plaintext_client_secret="new_client_secret", + pat=True, + ) + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.scm_integrations.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = await response.parse() + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.scm_integrations.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = await response.parse() + assert_matches_type(object, scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.list() + assert_matches_type(AsyncIntegrationsPage[ScmIntegration], scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.list( + token="token", + page_size=0, + filter={"runner_ids": ["d2c94c27-3b76-4a42-b88c-95a85e392c68"]}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncIntegrationsPage[ScmIntegration], scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.scm_integrations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = await response.parse() + assert_matches_type(AsyncIntegrationsPage[ScmIntegration], scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.scm_integrations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = await response.parse() + assert_matches_type(AsyncIntegrationsPage[ScmIntegration], scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.delete() + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + scm_integration = await async_client.runners.configurations.scm_integrations.delete( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.scm_integrations.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + scm_integration = await response.parse() + assert_matches_type(object, scm_integration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.scm_integrations.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + scm_integration = await response.parse() + assert_matches_type(object, scm_integration, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/runners/test_configurations.py b/tests/api_resources/runners/test_configurations.py new file mode 100644 index 0000000..94422e1 --- /dev/null +++ b/tests/api_resources/runners/test_configurations.py @@ -0,0 +1,142 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types.runners import ConfigurationValidateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestConfigurations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_validate(self, client: Gitpod) -> None: + configuration = client.runners.configurations.validate() + assert_matches_type(ConfigurationValidateResponse, configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_validate_with_all_params(self, client: Gitpod) -> None: + configuration = client.runners.configurations.validate( + environment_class={ + "id": "id", + "runner_id": "runnerId", + "configuration": [ + { + "key": "key", + "value": "value", + } + ], + "description": "xxx", + "display_name": "xxx", + "enabled": True, + }, + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + scm_integration={ + "id": "integration-id", + "host": "github.com", + "issuer_url": "issuerUrl", + "oauth_client_id": "client_id", + "oauth_encrypted_client_secret": "U3RhaW5sZXNzIHJvY2tz", + "oauth_plaintext_client_secret": "client_secret", + "pat": True, + "scm_id": "github", + }, + ) + assert_matches_type(ConfigurationValidateResponse, configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_validate(self, client: Gitpod) -> None: + response = client.runners.configurations.with_raw_response.validate() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + configuration = response.parse() + assert_matches_type(ConfigurationValidateResponse, configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_validate(self, client: Gitpod) -> None: + with client.runners.configurations.with_streaming_response.validate() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + configuration = response.parse() + assert_matches_type(ConfigurationValidateResponse, configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncConfigurations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_validate(self, async_client: AsyncGitpod) -> None: + configuration = await async_client.runners.configurations.validate() + assert_matches_type(ConfigurationValidateResponse, configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_validate_with_all_params(self, async_client: AsyncGitpod) -> None: + configuration = await async_client.runners.configurations.validate( + environment_class={ + "id": "id", + "runner_id": "runnerId", + "configuration": [ + { + "key": "key", + "value": "value", + } + ], + "description": "xxx", + "display_name": "xxx", + "enabled": True, + }, + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + scm_integration={ + "id": "integration-id", + "host": "github.com", + "issuer_url": "issuerUrl", + "oauth_client_id": "client_id", + "oauth_encrypted_client_secret": "U3RhaW5sZXNzIHJvY2tz", + "oauth_plaintext_client_secret": "client_secret", + "pat": True, + "scm_id": "github", + }, + ) + assert_matches_type(ConfigurationValidateResponse, configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_validate(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.configurations.with_raw_response.validate() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + configuration = await response.parse() + assert_matches_type(ConfigurationValidateResponse, configuration, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_validate(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.configurations.with_streaming_response.validate() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + configuration = await response.parse() + assert_matches_type(ConfigurationValidateResponse, configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/runners/test_policies.py b/tests/api_resources/runners/test_policies.py new file mode 100644 index 0000000..9f387dd --- /dev/null +++ b/tests/api_resources/runners/test_policies.py @@ -0,0 +1,339 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncPoliciesPage, AsyncPoliciesPage +from gitpod.types.runners import ( + RunnerPolicy, + PolicyCreateResponse, + PolicyUpdateResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPolicies: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + policy = client.runners.policies.create() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + policy = client.runners.policies.create( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + role="RUNNER_ROLE_ADMIN", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.runners.policies.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.runners.policies.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + policy = client.runners.policies.update() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + policy = client.runners.policies.update( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + role="RUNNER_ROLE_USER", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.runners.policies.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.runners.policies.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + policy = client.runners.policies.list() + assert_matches_type(SyncPoliciesPage[RunnerPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + policy = client.runners.policies.list( + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(SyncPoliciesPage[RunnerPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.runners.policies.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(SyncPoliciesPage[RunnerPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.runners.policies.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(SyncPoliciesPage[RunnerPolicy], policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + policy = client.runners.policies.delete() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + policy = client.runners.policies.delete( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.runners.policies.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.runners.policies.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(object, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPolicies: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + policy = await async_client.runners.policies.create() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.runners.policies.create( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + role="RUNNER_ROLE_ADMIN", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.policies.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.policies.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(PolicyCreateResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + policy = await async_client.runners.policies.update() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.runners.policies.update( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + role="RUNNER_ROLE_USER", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.policies.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.policies.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(PolicyUpdateResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + policy = await async_client.runners.policies.list() + assert_matches_type(AsyncPoliciesPage[RunnerPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.runners.policies.list( + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(AsyncPoliciesPage[RunnerPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.policies.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(AsyncPoliciesPage[RunnerPolicy], policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.policies.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(AsyncPoliciesPage[RunnerPolicy], policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + policy = await async_client.runners.policies.delete() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + policy = await async_client.runners.policies.delete( + group_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.policies.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(object, policy, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.policies.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(object, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_accounts.py b/tests/api_resources/test_accounts.py new file mode 100644 index 0000000..7955675 --- /dev/null +++ b/tests/api_resources/test_accounts.py @@ -0,0 +1,416 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import ( + LoginProvider, + AccountRetrieveResponse, + AccountGetSSOLoginURLResponse, + AccountListJoinableOrganizationsResponse, +) +from gitpod.pagination import SyncLoginProvidersPage, AsyncLoginProvidersPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAccounts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + account = client.accounts.retrieve() + assert_matches_type(AccountRetrieveResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + account = client.accounts.retrieve( + empty=True, + ) + assert_matches_type(AccountRetrieveResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.accounts.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = response.parse() + assert_matches_type(AccountRetrieveResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.accounts.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(AccountRetrieveResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + account = client.accounts.delete( + account_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(object, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.accounts.with_raw_response.delete( + account_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = response.parse() + assert_matches_type(object, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.accounts.with_streaming_response.delete( + account_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(object, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_get_sso_login_url(self, client: Gitpod) -> None: + account = client.accounts.get_sso_login_url( + email="user@company.com", + ) + assert_matches_type(AccountGetSSOLoginURLResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_get_sso_login_url_with_all_params(self, client: Gitpod) -> None: + account = client.accounts.get_sso_login_url( + email="user@company.com", + return_to="https://example.com", + ) + assert_matches_type(AccountGetSSOLoginURLResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_get_sso_login_url(self, client: Gitpod) -> None: + response = client.accounts.with_raw_response.get_sso_login_url( + email="user@company.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = response.parse() + assert_matches_type(AccountGetSSOLoginURLResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_get_sso_login_url(self, client: Gitpod) -> None: + with client.accounts.with_streaming_response.get_sso_login_url( + email="user@company.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(AccountGetSSOLoginURLResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list_joinable_organizations(self, client: Gitpod) -> None: + account = client.accounts.list_joinable_organizations() + assert_matches_type(AccountListJoinableOrganizationsResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_joinable_organizations_with_all_params(self, client: Gitpod) -> None: + account = client.accounts.list_joinable_organizations( + token="token", + page_size=0, + empty=True, + ) + assert_matches_type(AccountListJoinableOrganizationsResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list_joinable_organizations(self, client: Gitpod) -> None: + response = client.accounts.with_raw_response.list_joinable_organizations() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = response.parse() + assert_matches_type(AccountListJoinableOrganizationsResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list_joinable_organizations(self, client: Gitpod) -> None: + with client.accounts.with_streaming_response.list_joinable_organizations() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(AccountListJoinableOrganizationsResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list_login_providers(self, client: Gitpod) -> None: + account = client.accounts.list_login_providers() + assert_matches_type(SyncLoginProvidersPage[LoginProvider], account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_login_providers_with_all_params(self, client: Gitpod) -> None: + account = client.accounts.list_login_providers( + token="token", + page_size=0, + filter={"invite_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncLoginProvidersPage[LoginProvider], account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list_login_providers(self, client: Gitpod) -> None: + response = client.accounts.with_raw_response.list_login_providers() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = response.parse() + assert_matches_type(SyncLoginProvidersPage[LoginProvider], account, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list_login_providers(self, client: Gitpod) -> None: + with client.accounts.with_streaming_response.list_login_providers() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = response.parse() + assert_matches_type(SyncLoginProvidersPage[LoginProvider], account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAccounts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.retrieve() + assert_matches_type(AccountRetrieveResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.retrieve( + empty=True, + ) + assert_matches_type(AccountRetrieveResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.accounts.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = await response.parse() + assert_matches_type(AccountRetrieveResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.accounts.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(AccountRetrieveResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.delete( + account_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(object, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.accounts.with_raw_response.delete( + account_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = await response.parse() + assert_matches_type(object, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.accounts.with_streaming_response.delete( + account_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(object, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_get_sso_login_url(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.get_sso_login_url( + email="user@company.com", + ) + assert_matches_type(AccountGetSSOLoginURLResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_get_sso_login_url_with_all_params(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.get_sso_login_url( + email="user@company.com", + return_to="https://example.com", + ) + assert_matches_type(AccountGetSSOLoginURLResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_get_sso_login_url(self, async_client: AsyncGitpod) -> None: + response = await async_client.accounts.with_raw_response.get_sso_login_url( + email="user@company.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = await response.parse() + assert_matches_type(AccountGetSSOLoginURLResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_get_sso_login_url(self, async_client: AsyncGitpod) -> None: + async with async_client.accounts.with_streaming_response.get_sso_login_url( + email="user@company.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(AccountGetSSOLoginURLResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list_joinable_organizations(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.list_joinable_organizations() + assert_matches_type(AccountListJoinableOrganizationsResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_joinable_organizations_with_all_params(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.list_joinable_organizations( + token="token", + page_size=0, + empty=True, + ) + assert_matches_type(AccountListJoinableOrganizationsResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list_joinable_organizations(self, async_client: AsyncGitpod) -> None: + response = await async_client.accounts.with_raw_response.list_joinable_organizations() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = await response.parse() + assert_matches_type(AccountListJoinableOrganizationsResponse, account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list_joinable_organizations(self, async_client: AsyncGitpod) -> None: + async with async_client.accounts.with_streaming_response.list_joinable_organizations() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(AccountListJoinableOrganizationsResponse, account, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list_login_providers(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.list_login_providers() + assert_matches_type(AsyncLoginProvidersPage[LoginProvider], account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_login_providers_with_all_params(self, async_client: AsyncGitpod) -> None: + account = await async_client.accounts.list_login_providers( + token="token", + page_size=0, + filter={"invite_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncLoginProvidersPage[LoginProvider], account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list_login_providers(self, async_client: AsyncGitpod) -> None: + response = await async_client.accounts.with_raw_response.list_login_providers() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + account = await response.parse() + assert_matches_type(AsyncLoginProvidersPage[LoginProvider], account, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list_login_providers(self, async_client: AsyncGitpod) -> None: + async with async_client.accounts.with_streaming_response.list_login_providers() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + account = await response.parse() + assert_matches_type(AsyncLoginProvidersPage[LoginProvider], account, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_editors.py b/tests/api_resources/test_editors.py new file mode 100644 index 0000000..14b2938 --- /dev/null +++ b/tests/api_resources/test_editors.py @@ -0,0 +1,261 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import ( + Editor, + EditorRetrieveResponse, + EditorResolveURLResponse, +) +from gitpod.pagination import SyncEditorsPage, AsyncEditorsPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestEditors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + editor = client.editors.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(EditorRetrieveResponse, editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.editors.with_raw_response.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + editor = response.parse() + assert_matches_type(EditorRetrieveResponse, editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.editors.with_streaming_response.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + editor = response.parse() + assert_matches_type(EditorRetrieveResponse, editor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + editor = client.editors.list() + assert_matches_type(SyncEditorsPage[Editor], editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + editor = client.editors.list( + token="token", + page_size=0, + filter={"allowed_by_policy": True}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncEditorsPage[Editor], editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.editors.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + editor = response.parse() + assert_matches_type(SyncEditorsPage[Editor], editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.editors.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + editor = response.parse() + assert_matches_type(SyncEditorsPage[Editor], editor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_resolve_url(self, client: Gitpod) -> None: + editor = client.editors.resolve_url( + editor_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(EditorResolveURLResponse, editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_resolve_url(self, client: Gitpod) -> None: + response = client.editors.with_raw_response.resolve_url( + editor_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + editor = response.parse() + assert_matches_type(EditorResolveURLResponse, editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_resolve_url(self, client: Gitpod) -> None: + with client.editors.with_streaming_response.resolve_url( + editor_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + editor = response.parse() + assert_matches_type(EditorResolveURLResponse, editor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncEditors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + editor = await async_client.editors.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(EditorRetrieveResponse, editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.editors.with_raw_response.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + editor = await response.parse() + assert_matches_type(EditorRetrieveResponse, editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.editors.with_streaming_response.retrieve( + id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + editor = await response.parse() + assert_matches_type(EditorRetrieveResponse, editor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + editor = await async_client.editors.list() + assert_matches_type(AsyncEditorsPage[Editor], editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + editor = await async_client.editors.list( + token="token", + page_size=0, + filter={"allowed_by_policy": True}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncEditorsPage[Editor], editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.editors.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + editor = await response.parse() + assert_matches_type(AsyncEditorsPage[Editor], editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.editors.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + editor = await response.parse() + assert_matches_type(AsyncEditorsPage[Editor], editor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_resolve_url(self, async_client: AsyncGitpod) -> None: + editor = await async_client.editors.resolve_url( + editor_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(EditorResolveURLResponse, editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_resolve_url(self, async_client: AsyncGitpod) -> None: + response = await async_client.editors.with_raw_response.resolve_url( + editor_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + editor = await response.parse() + assert_matches_type(EditorResolveURLResponse, editor, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_resolve_url(self, async_client: AsyncGitpod) -> None: + async with async_client.editors.with_streaming_response.resolve_url( + editor_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + editor = await response.parse() + assert_matches_type(EditorResolveURLResponse, editor, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_environments.py b/tests/api_resources/test_environments.py new file mode 100644 index 0000000..861ebc4 --- /dev/null +++ b/tests/api_resources/test_environments.py @@ -0,0 +1,1271 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import ( + Environment, + EnvironmentCreateResponse, + EnvironmentRetrieveResponse, + EnvironmentCreateLogsTokenResponse, + EnvironmentCreateFromProjectResponse, + EnvironmentCreateEnvironmentTokenResponse, +) +from gitpod._utils import parse_datetime +from gitpod.pagination import SyncEnvironmentsPage, AsyncEnvironmentsPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestEnvironments: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + environment = client.environments.create() + assert_matches_type(EnvironmentCreateResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.create( + spec={ + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "automations_file": { + "automations_file_path": "automationsFilePath", + "session": "session", + }, + "content": { + "git_email": "gitEmail", + "git_username": "gitUsername", + "initializer": { + "specs": [ + { + "context_url": {"url": "https://github.com/gitpod-io/gitpod"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "remoteUri", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + "session": "session", + }, + "desired_phase": "ENVIRONMENT_PHASE_UNSPECIFIED", + "devcontainer": { + "default_devcontainer_image": "defaultDevcontainerImage", + "devcontainer_file_path": "devcontainerFilePath", + "dotfiles": {"repository": "https://example.com"}, + "session": "session", + }, + "machine": { + "class": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "session": "session", + }, + "ports": [ + { + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "name": "x", + "port": 1, + } + ], + "secrets": [ + { + "id": "id", + "container_registry_basic_auth_host": "containerRegistryBasicAuthHost", + "environment_variable": "environmentVariable", + "file_path": "filePath", + "git_credential_host": "gitCredentialHost", + "name": "name", + "session": "session", + "source": "source", + "source_ref": "sourceRef", + } + ], + "spec_version": "specVersion", + "ssh_public_keys": [ + { + "id": "id", + "value": "value", + } + ], + "timeout": {"disconnected": "+9125115.360s"}, + }, + ) + assert_matches_type(EnvironmentCreateResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(EnvironmentCreateResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(EnvironmentCreateResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + environment = client.environments.retrieve( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(EnvironmentRetrieveResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.retrieve( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(EnvironmentRetrieveResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.retrieve( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(EnvironmentRetrieveResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + environment = client.environments.update() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.update( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + metadata={"name": "name"}, + spec={ + "automations_file": { + "automations_file_path": "automationsFilePath", + "session": "session", + }, + "content": { + "git_email": "gitEmail", + "git_username": "gitUsername", + "initializer": { + "specs": [ + { + "context_url": {"url": "https://example.com"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "remoteUri", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + "session": "session", + }, + "devcontainer": { + "devcontainer_file_path": "devcontainerFilePath", + "session": "session", + }, + "ports": [ + { + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "name": "x", + "port": 1, + } + ], + "ssh_public_keys": [ + { + "id": "0194b7c1-c954-718d-91a4-9a742aa5fc11", + "value": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...", + } + ], + "timeout": {"disconnected": "+9125115.360s"}, + }, + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + environment = client.environments.list() + assert_matches_type(SyncEnvironmentsPage[Environment], environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.list( + token="token", + page_size=0, + filter={ + "archival_status": "ARCHIVAL_STATUS_UNSPECIFIED", + "creator_ids": ["f53d2330-3795-4c5d-a1f3-453121af9c60"], + "project_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "runner_ids": ["e6aa9c54-89d3-42c1-ac31-bd8d8f1concentrate"], + "runner_kinds": ["RUNNER_KIND_UNSPECIFIED"], + "status_phases": ["ENVIRONMENT_PHASE_UNSPECIFIED"], + }, + pagination={ + "token": "token", + "page_size": 100, + }, + ) + assert_matches_type(SyncEnvironmentsPage[Environment], environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(SyncEnvironmentsPage[Environment], environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(SyncEnvironmentsPage[Environment], environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + environment = client.environments.delete() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.delete( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + force=False, + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_create_environment_token(self, client: Gitpod) -> None: + environment = client.environments.create_environment_token( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(EnvironmentCreateEnvironmentTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create_environment_token(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.create_environment_token( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(EnvironmentCreateEnvironmentTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create_environment_token(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.create_environment_token( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(EnvironmentCreateEnvironmentTokenResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_create_from_project(self, client: Gitpod) -> None: + environment = client.environments.create_from_project() + assert_matches_type(EnvironmentCreateFromProjectResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_from_project_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.create_from_project( + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + spec={ + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "automations_file": { + "automations_file_path": "automationsFilePath", + "session": "session", + }, + "content": { + "git_email": "gitEmail", + "git_username": "gitUsername", + "initializer": { + "specs": [ + { + "context_url": {"url": "https://example.com"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "remoteUri", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + "session": "session", + }, + "desired_phase": "ENVIRONMENT_PHASE_UNSPECIFIED", + "devcontainer": { + "default_devcontainer_image": "defaultDevcontainerImage", + "devcontainer_file_path": "devcontainerFilePath", + "dotfiles": {"repository": "https://example.com"}, + "session": "session", + }, + "machine": { + "class": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "session": "session", + }, + "ports": [ + { + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "name": "x", + "port": 1, + } + ], + "secrets": [ + { + "id": "id", + "container_registry_basic_auth_host": "containerRegistryBasicAuthHost", + "environment_variable": "environmentVariable", + "file_path": "filePath", + "git_credential_host": "gitCredentialHost", + "name": "name", + "session": "session", + "source": "source", + "source_ref": "sourceRef", + } + ], + "spec_version": "specVersion", + "ssh_public_keys": [ + { + "id": "id", + "value": "value", + } + ], + "timeout": {"disconnected": "14400s"}, + }, + ) + assert_matches_type(EnvironmentCreateFromProjectResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create_from_project(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.create_from_project() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(EnvironmentCreateFromProjectResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create_from_project(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.create_from_project() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(EnvironmentCreateFromProjectResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_create_logs_token(self, client: Gitpod) -> None: + environment = client.environments.create_logs_token() + assert_matches_type(EnvironmentCreateLogsTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_logs_token_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.create_logs_token( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(EnvironmentCreateLogsTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create_logs_token(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.create_logs_token() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(EnvironmentCreateLogsTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create_logs_token(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.create_logs_token() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(EnvironmentCreateLogsTokenResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_mark_active(self, client: Gitpod) -> None: + environment = client.environments.mark_active() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_mark_active_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.mark_active( + activity_signal={ + "source": "VS Code", + "timestamp": parse_datetime("2025-02-12T14:30:00Z"), + }, + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_mark_active(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.mark_active() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_mark_active(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.mark_active() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_start(self, client: Gitpod) -> None: + environment = client.environments.start() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_start_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.start( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_start(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.start() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_start(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.start() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_stop(self, client: Gitpod) -> None: + environment = client.environments.stop() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_stop_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.stop( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_stop(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.stop() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_stop(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.stop() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_unarchive(self, client: Gitpod) -> None: + environment = client.environments.unarchive() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_unarchive_with_all_params(self, client: Gitpod) -> None: + environment = client.environments.unarchive( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_unarchive(self, client: Gitpod) -> None: + response = client.environments.with_raw_response.unarchive() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_unarchive(self, client: Gitpod) -> None: + with client.environments.with_streaming_response.unarchive() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncEnvironments: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.create() + assert_matches_type(EnvironmentCreateResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.create( + spec={ + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "automations_file": { + "automations_file_path": "automationsFilePath", + "session": "session", + }, + "content": { + "git_email": "gitEmail", + "git_username": "gitUsername", + "initializer": { + "specs": [ + { + "context_url": {"url": "https://github.com/gitpod-io/gitpod"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "remoteUri", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + "session": "session", + }, + "desired_phase": "ENVIRONMENT_PHASE_UNSPECIFIED", + "devcontainer": { + "default_devcontainer_image": "defaultDevcontainerImage", + "devcontainer_file_path": "devcontainerFilePath", + "dotfiles": {"repository": "https://example.com"}, + "session": "session", + }, + "machine": { + "class": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "session": "session", + }, + "ports": [ + { + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "name": "x", + "port": 1, + } + ], + "secrets": [ + { + "id": "id", + "container_registry_basic_auth_host": "containerRegistryBasicAuthHost", + "environment_variable": "environmentVariable", + "file_path": "filePath", + "git_credential_host": "gitCredentialHost", + "name": "name", + "session": "session", + "source": "source", + "source_ref": "sourceRef", + } + ], + "spec_version": "specVersion", + "ssh_public_keys": [ + { + "id": "id", + "value": "value", + } + ], + "timeout": {"disconnected": "+9125115.360s"}, + }, + ) + assert_matches_type(EnvironmentCreateResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(EnvironmentCreateResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(EnvironmentCreateResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.retrieve( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(EnvironmentRetrieveResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.retrieve( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(EnvironmentRetrieveResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.retrieve( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(EnvironmentRetrieveResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.update() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.update( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + metadata={"name": "name"}, + spec={ + "automations_file": { + "automations_file_path": "automationsFilePath", + "session": "session", + }, + "content": { + "git_email": "gitEmail", + "git_username": "gitUsername", + "initializer": { + "specs": [ + { + "context_url": {"url": "https://example.com"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "remoteUri", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + "session": "session", + }, + "devcontainer": { + "devcontainer_file_path": "devcontainerFilePath", + "session": "session", + }, + "ports": [ + { + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "name": "x", + "port": 1, + } + ], + "ssh_public_keys": [ + { + "id": "0194b7c1-c954-718d-91a4-9a742aa5fc11", + "value": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...", + } + ], + "timeout": {"disconnected": "+9125115.360s"}, + }, + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.list() + assert_matches_type(AsyncEnvironmentsPage[Environment], environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.list( + token="token", + page_size=0, + filter={ + "archival_status": "ARCHIVAL_STATUS_UNSPECIFIED", + "creator_ids": ["f53d2330-3795-4c5d-a1f3-453121af9c60"], + "project_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "runner_ids": ["e6aa9c54-89d3-42c1-ac31-bd8d8f1concentrate"], + "runner_kinds": ["RUNNER_KIND_UNSPECIFIED"], + "status_phases": ["ENVIRONMENT_PHASE_UNSPECIFIED"], + }, + pagination={ + "token": "token", + "page_size": 100, + }, + ) + assert_matches_type(AsyncEnvironmentsPage[Environment], environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(AsyncEnvironmentsPage[Environment], environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(AsyncEnvironmentsPage[Environment], environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.delete() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.delete( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + force=False, + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_create_environment_token(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.create_environment_token( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(EnvironmentCreateEnvironmentTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create_environment_token(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.create_environment_token( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(EnvironmentCreateEnvironmentTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create_environment_token(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.create_environment_token( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(EnvironmentCreateEnvironmentTokenResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_create_from_project(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.create_from_project() + assert_matches_type(EnvironmentCreateFromProjectResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_from_project_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.create_from_project( + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + spec={ + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "automations_file": { + "automations_file_path": "automationsFilePath", + "session": "session", + }, + "content": { + "git_email": "gitEmail", + "git_username": "gitUsername", + "initializer": { + "specs": [ + { + "context_url": {"url": "https://example.com"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "remoteUri", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + "session": "session", + }, + "desired_phase": "ENVIRONMENT_PHASE_UNSPECIFIED", + "devcontainer": { + "default_devcontainer_image": "defaultDevcontainerImage", + "devcontainer_file_path": "devcontainerFilePath", + "dotfiles": {"repository": "https://example.com"}, + "session": "session", + }, + "machine": { + "class": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "session": "session", + }, + "ports": [ + { + "admission": "ADMISSION_LEVEL_UNSPECIFIED", + "name": "x", + "port": 1, + } + ], + "secrets": [ + { + "id": "id", + "container_registry_basic_auth_host": "containerRegistryBasicAuthHost", + "environment_variable": "environmentVariable", + "file_path": "filePath", + "git_credential_host": "gitCredentialHost", + "name": "name", + "session": "session", + "source": "source", + "source_ref": "sourceRef", + } + ], + "spec_version": "specVersion", + "ssh_public_keys": [ + { + "id": "id", + "value": "value", + } + ], + "timeout": {"disconnected": "14400s"}, + }, + ) + assert_matches_type(EnvironmentCreateFromProjectResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create_from_project(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.create_from_project() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(EnvironmentCreateFromProjectResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create_from_project(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.create_from_project() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(EnvironmentCreateFromProjectResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_create_logs_token(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.create_logs_token() + assert_matches_type(EnvironmentCreateLogsTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_logs_token_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.create_logs_token( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(EnvironmentCreateLogsTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create_logs_token(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.create_logs_token() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(EnvironmentCreateLogsTokenResponse, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create_logs_token(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.create_logs_token() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(EnvironmentCreateLogsTokenResponse, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_mark_active(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.mark_active() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_mark_active_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.mark_active( + activity_signal={ + "source": "VS Code", + "timestamp": parse_datetime("2025-02-12T14:30:00Z"), + }, + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_mark_active(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.mark_active() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_mark_active(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.mark_active() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_start(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.start() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_start_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.start( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_start(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.start() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_start(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.start() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_stop(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.stop() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_stop_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.stop( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_stop(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.stop() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_stop(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.stop() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_unarchive(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.unarchive() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_unarchive_with_all_params(self, async_client: AsyncGitpod) -> None: + environment = await async_client.environments.unarchive( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + ) + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_unarchive(self, async_client: AsyncGitpod) -> None: + response = await async_client.environments.with_raw_response.unarchive() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_unarchive(self, async_client: AsyncGitpod) -> None: + async with async_client.environments.with_streaming_response.unarchive() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + environment = await response.parse() + assert_matches_type(object, environment, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_events.py b/tests/api_resources/test_events.py new file mode 100644 index 0000000..20a56a2 --- /dev/null +++ b/tests/api_resources/test_events.py @@ -0,0 +1,192 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import EventListResponse, EventWatchResponse +from gitpod.pagination import SyncEntriesPage, AsyncEntriesPage +from gitpod._decoders.jsonl import JSONLDecoder, AsyncJSONLDecoder + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestEvents: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + event = client.events.list() + assert_matches_type(SyncEntriesPage[EventListResponse], event, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + event = client.events.list( + token="token", + page_size=0, + filter={ + "actor_ids": ["d2c94c27-3b76-4a42-b88c-95a85e392c68"], + "actor_principals": ["PRINCIPAL_USER"], + "subject_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "subject_types": ["RESOURCE_TYPE_UNSPECIFIED"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncEntriesPage[EventListResponse], event, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.events.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + event = response.parse() + assert_matches_type(SyncEntriesPage[EventListResponse], event, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.events.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + event = response.parse() + assert_matches_type(SyncEntriesPage[EventListResponse], event, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support JSONL responses yet") + @parametrize + def test_method_watch(self, client: Gitpod) -> None: + event_stream = client.events.watch() + assert_matches_type(JSONLDecoder[EventWatchResponse], event_stream, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support JSONL responses yet") + @parametrize + def test_method_watch_with_all_params(self, client: Gitpod) -> None: + event_stream = client.events.watch( + environment_id="environmentId", + organization=True, + ) + assert_matches_type(JSONLDecoder[EventWatchResponse], event_stream, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support JSONL responses yet") + @parametrize + def test_raw_response_watch(self, client: Gitpod) -> None: + response = client.events.with_raw_response.watch() + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + stream.close() + + @pytest.mark.skip(reason="Prism doesn't support JSONL responses yet") + @parametrize + def test_streaming_response_watch(self, client: Gitpod) -> None: + with client.events.with_streaming_response.watch() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() + + assert cast(Any, response.is_closed) is True + + +class TestAsyncEvents: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + event = await async_client.events.list() + assert_matches_type(AsyncEntriesPage[EventListResponse], event, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + event = await async_client.events.list( + token="token", + page_size=0, + filter={ + "actor_ids": ["d2c94c27-3b76-4a42-b88c-95a85e392c68"], + "actor_principals": ["PRINCIPAL_USER"], + "subject_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "subject_types": ["RESOURCE_TYPE_UNSPECIFIED"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncEntriesPage[EventListResponse], event, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.events.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + event = await response.parse() + assert_matches_type(AsyncEntriesPage[EventListResponse], event, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.events.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + event = await response.parse() + assert_matches_type(AsyncEntriesPage[EventListResponse], event, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support JSONL responses yet") + @parametrize + async def test_method_watch(self, async_client: AsyncGitpod) -> None: + event_stream = await async_client.events.watch() + assert_matches_type(AsyncJSONLDecoder[EventWatchResponse], event_stream, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support JSONL responses yet") + @parametrize + async def test_method_watch_with_all_params(self, async_client: AsyncGitpod) -> None: + event_stream = await async_client.events.watch( + environment_id="environmentId", + organization=True, + ) + assert_matches_type(AsyncJSONLDecoder[EventWatchResponse], event_stream, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support JSONL responses yet") + @parametrize + async def test_raw_response_watch(self, async_client: AsyncGitpod) -> None: + response = await async_client.events.with_raw_response.watch() + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + await stream.close() + + @pytest.mark.skip(reason="Prism doesn't support JSONL responses yet") + @parametrize + async def test_streaming_response_watch(self, async_client: AsyncGitpod) -> None: + async with async_client.events.with_streaming_response.watch() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_gateways.py b/tests/api_resources/test_gateways.py new file mode 100644 index 0000000..d4684fb --- /dev/null +++ b/tests/api_resources/test_gateways.py @@ -0,0 +1,107 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncGatewaysPage, AsyncGatewaysPage +from gitpod.types.shared import Gateway + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestGateways: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + gateway = client.gateways.list() + assert_matches_type(SyncGatewaysPage[Gateway], gateway, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + gateway = client.gateways.list( + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 100, + }, + ) + assert_matches_type(SyncGatewaysPage[Gateway], gateway, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.gateways.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + gateway = response.parse() + assert_matches_type(SyncGatewaysPage[Gateway], gateway, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.gateways.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + gateway = response.parse() + assert_matches_type(SyncGatewaysPage[Gateway], gateway, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncGateways: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + gateway = await async_client.gateways.list() + assert_matches_type(AsyncGatewaysPage[Gateway], gateway, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + gateway = await async_client.gateways.list( + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 100, + }, + ) + assert_matches_type(AsyncGatewaysPage[Gateway], gateway, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.gateways.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + gateway = await response.parse() + assert_matches_type(AsyncGatewaysPage[Gateway], gateway, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.gateways.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + gateway = await response.parse() + assert_matches_type(AsyncGatewaysPage[Gateway], gateway, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_groups.py b/tests/api_resources/test_groups.py new file mode 100644 index 0000000..e0f0936 --- /dev/null +++ b/tests/api_resources/test_groups.py @@ -0,0 +1,107 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import Group +from gitpod.pagination import SyncGroupsPage, AsyncGroupsPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + group = client.groups.list() + assert_matches_type(SyncGroupsPage[Group], group, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + group = client.groups.list( + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncGroupsPage[Group], group, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.groups.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = response.parse() + assert_matches_type(SyncGroupsPage[Group], group, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.groups.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = response.parse() + assert_matches_type(SyncGroupsPage[Group], group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + group = await async_client.groups.list() + assert_matches_type(AsyncGroupsPage[Group], group, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + group = await async_client.groups.list( + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncGroupsPage[Group], group, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.groups.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + group = await response.parse() + assert_matches_type(AsyncGroupsPage[Group], group, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.groups.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + group = await response.parse() + assert_matches_type(AsyncGroupsPage[Group], group, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_identity.py b/tests/api_resources/test_identity.py new file mode 100644 index 0000000..5fbbe49 --- /dev/null +++ b/tests/api_resources/test_identity.py @@ -0,0 +1,246 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import ( + IdentityGetIDTokenResponse, + IdentityExchangeTokenResponse, + IdentityGetAuthenticatedIdentityResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestIdentity: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_exchange_token(self, client: Gitpod) -> None: + identity = client.identity.exchange_token() + assert_matches_type(IdentityExchangeTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_exchange_token_with_all_params(self, client: Gitpod) -> None: + identity = client.identity.exchange_token( + exchange_token="exchange-token-value", + ) + assert_matches_type(IdentityExchangeTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_exchange_token(self, client: Gitpod) -> None: + response = client.identity.with_raw_response.exchange_token() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + identity = response.parse() + assert_matches_type(IdentityExchangeTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_exchange_token(self, client: Gitpod) -> None: + with client.identity.with_streaming_response.exchange_token() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + identity = response.parse() + assert_matches_type(IdentityExchangeTokenResponse, identity, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_get_authenticated_identity(self, client: Gitpod) -> None: + identity = client.identity.get_authenticated_identity() + assert_matches_type(IdentityGetAuthenticatedIdentityResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_get_authenticated_identity_with_all_params(self, client: Gitpod) -> None: + identity = client.identity.get_authenticated_identity( + empty=True, + ) + assert_matches_type(IdentityGetAuthenticatedIdentityResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_get_authenticated_identity(self, client: Gitpod) -> None: + response = client.identity.with_raw_response.get_authenticated_identity() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + identity = response.parse() + assert_matches_type(IdentityGetAuthenticatedIdentityResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_get_authenticated_identity(self, client: Gitpod) -> None: + with client.identity.with_streaming_response.get_authenticated_identity() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + identity = response.parse() + assert_matches_type(IdentityGetAuthenticatedIdentityResponse, identity, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_get_id_token(self, client: Gitpod) -> None: + identity = client.identity.get_id_token() + assert_matches_type(IdentityGetIDTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_get_id_token_with_all_params(self, client: Gitpod) -> None: + identity = client.identity.get_id_token( + audience=["https://api.gitpod.io", "https://ws.gitpod.io"], + version="ID_TOKEN_VERSION_UNSPECIFIED", + ) + assert_matches_type(IdentityGetIDTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_get_id_token(self, client: Gitpod) -> None: + response = client.identity.with_raw_response.get_id_token() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + identity = response.parse() + assert_matches_type(IdentityGetIDTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_get_id_token(self, client: Gitpod) -> None: + with client.identity.with_streaming_response.get_id_token() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + identity = response.parse() + assert_matches_type(IdentityGetIDTokenResponse, identity, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncIdentity: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_exchange_token(self, async_client: AsyncGitpod) -> None: + identity = await async_client.identity.exchange_token() + assert_matches_type(IdentityExchangeTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_exchange_token_with_all_params(self, async_client: AsyncGitpod) -> None: + identity = await async_client.identity.exchange_token( + exchange_token="exchange-token-value", + ) + assert_matches_type(IdentityExchangeTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_exchange_token(self, async_client: AsyncGitpod) -> None: + response = await async_client.identity.with_raw_response.exchange_token() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + identity = await response.parse() + assert_matches_type(IdentityExchangeTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_exchange_token(self, async_client: AsyncGitpod) -> None: + async with async_client.identity.with_streaming_response.exchange_token() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + identity = await response.parse() + assert_matches_type(IdentityExchangeTokenResponse, identity, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_get_authenticated_identity(self, async_client: AsyncGitpod) -> None: + identity = await async_client.identity.get_authenticated_identity() + assert_matches_type(IdentityGetAuthenticatedIdentityResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_get_authenticated_identity_with_all_params(self, async_client: AsyncGitpod) -> None: + identity = await async_client.identity.get_authenticated_identity( + empty=True, + ) + assert_matches_type(IdentityGetAuthenticatedIdentityResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_get_authenticated_identity(self, async_client: AsyncGitpod) -> None: + response = await async_client.identity.with_raw_response.get_authenticated_identity() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + identity = await response.parse() + assert_matches_type(IdentityGetAuthenticatedIdentityResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_get_authenticated_identity(self, async_client: AsyncGitpod) -> None: + async with async_client.identity.with_streaming_response.get_authenticated_identity() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + identity = await response.parse() + assert_matches_type(IdentityGetAuthenticatedIdentityResponse, identity, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_get_id_token(self, async_client: AsyncGitpod) -> None: + identity = await async_client.identity.get_id_token() + assert_matches_type(IdentityGetIDTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_get_id_token_with_all_params(self, async_client: AsyncGitpod) -> None: + identity = await async_client.identity.get_id_token( + audience=["https://api.gitpod.io", "https://ws.gitpod.io"], + version="ID_TOKEN_VERSION_UNSPECIFIED", + ) + assert_matches_type(IdentityGetIDTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_get_id_token(self, async_client: AsyncGitpod) -> None: + response = await async_client.identity.with_raw_response.get_id_token() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + identity = await response.parse() + assert_matches_type(IdentityGetIDTokenResponse, identity, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_get_id_token(self, async_client: AsyncGitpod) -> None: + async with async_client.identity.with_streaming_response.get_id_token() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + identity = await response.parse() + assert_matches_type(IdentityGetIDTokenResponse, identity, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_organizations.py b/tests/api_resources/test_organizations.py new file mode 100644 index 0000000..69138c9 --- /dev/null +++ b/tests/api_resources/test_organizations.py @@ -0,0 +1,675 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import ( + OrganizationMember, + OrganizationJoinResponse, + OrganizationCreateResponse, + OrganizationUpdateResponse, + OrganizationRetrieveResponse, +) +from gitpod.pagination import SyncMembersPage, AsyncMembersPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestOrganizations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + organization = client.organizations.create( + name="Acme Corp Engineering", + ) + assert_matches_type(OrganizationCreateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + organization = client.organizations.create( + name="Acme Corp Engineering", + invite_accounts_with_matching_domain=True, + join_organization=True, + ) + assert_matches_type(OrganizationCreateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.organizations.with_raw_response.create( + name="Acme Corp Engineering", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(OrganizationCreateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.organizations.with_streaming_response.create( + name="Acme Corp Engineering", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(OrganizationCreateResponse, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + organization = client.organizations.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(OrganizationRetrieveResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.organizations.with_raw_response.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(OrganizationRetrieveResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.organizations.with_streaming_response.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(OrganizationRetrieveResponse, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + organization = client.organizations.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(OrganizationUpdateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + organization = client.organizations.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + invite_domains={"domains": ["sfN2.l.iJR-BU.u9JV9.a.m.o2D-4b-Jd.0Z-kX.L.n.S.f.UKbxB"]}, + name="name", + ) + assert_matches_type(OrganizationUpdateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.organizations.with_raw_response.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(OrganizationUpdateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.organizations.with_streaming_response.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(OrganizationUpdateResponse, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + organization = client.organizations.delete( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.organizations.with_raw_response.delete( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.organizations.with_streaming_response.delete( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(object, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_join(self, client: Gitpod) -> None: + organization = client.organizations.join() + assert_matches_type(OrganizationJoinResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_join_with_all_params(self, client: Gitpod) -> None: + organization = client.organizations.join( + invite_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(OrganizationJoinResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_join(self, client: Gitpod) -> None: + response = client.organizations.with_raw_response.join() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(OrganizationJoinResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_join(self, client: Gitpod) -> None: + with client.organizations.with_streaming_response.join() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(OrganizationJoinResponse, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_leave(self, client: Gitpod) -> None: + organization = client.organizations.leave( + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_leave(self, client: Gitpod) -> None: + response = client.organizations.with_raw_response.leave( + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_leave(self, client: Gitpod) -> None: + with client.organizations.with_streaming_response.leave( + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(object, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list_members(self, client: Gitpod) -> None: + organization = client.organizations.list_members( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(SyncMembersPage[OrganizationMember], organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_members_with_all_params(self, client: Gitpod) -> None: + organization = client.organizations.list_members( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncMembersPage[OrganizationMember], organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list_members(self, client: Gitpod) -> None: + response = client.organizations.with_raw_response.list_members( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(SyncMembersPage[OrganizationMember], organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list_members(self, client: Gitpod) -> None: + with client.organizations.with_streaming_response.list_members( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(SyncMembersPage[OrganizationMember], organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_set_role(self, client: Gitpod) -> None: + organization = client.organizations.set_role( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_set_role_with_all_params(self, client: Gitpod) -> None: + organization = client.organizations.set_role( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + role="ORGANIZATION_ROLE_MEMBER", + ) + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_set_role(self, client: Gitpod) -> None: + response = client.organizations.with_raw_response.set_role( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_set_role(self, client: Gitpod) -> None: + with client.organizations.with_streaming_response.set_role( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(object, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncOrganizations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.create( + name="Acme Corp Engineering", + ) + assert_matches_type(OrganizationCreateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.create( + name="Acme Corp Engineering", + invite_accounts_with_matching_domain=True, + join_organization=True, + ) + assert_matches_type(OrganizationCreateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.with_raw_response.create( + name="Acme Corp Engineering", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(OrganizationCreateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.with_streaming_response.create( + name="Acme Corp Engineering", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(OrganizationCreateResponse, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(OrganizationRetrieveResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.with_raw_response.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(OrganizationRetrieveResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.with_streaming_response.retrieve( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(OrganizationRetrieveResponse, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(OrganizationUpdateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + invite_domains={"domains": ["sfN2.l.iJR-BU.u9JV9.a.m.o2D-4b-Jd.0Z-kX.L.n.S.f.UKbxB"]}, + name="name", + ) + assert_matches_type(OrganizationUpdateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.with_raw_response.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(OrganizationUpdateResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.with_streaming_response.update( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(OrganizationUpdateResponse, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.delete( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.with_raw_response.delete( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.with_streaming_response.delete( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(object, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_join(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.join() + assert_matches_type(OrganizationJoinResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_join_with_all_params(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.join( + invite_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(OrganizationJoinResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_join(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.with_raw_response.join() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(OrganizationJoinResponse, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_join(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.with_streaming_response.join() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(OrganizationJoinResponse, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_leave(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.leave( + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_leave(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.with_raw_response.leave( + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_leave(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.with_streaming_response.leave( + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(object, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list_members(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.list_members( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(AsyncMembersPage[OrganizationMember], organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_members_with_all_params(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.list_members( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + token="token", + page_size=0, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncMembersPage[OrganizationMember], organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list_members(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.with_raw_response.list_members( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(AsyncMembersPage[OrganizationMember], organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list_members(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.with_streaming_response.list_members( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(AsyncMembersPage[OrganizationMember], organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_set_role(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.set_role( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_set_role_with_all_params(self, async_client: AsyncGitpod) -> None: + organization = await async_client.organizations.set_role( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + role="ORGANIZATION_ROLE_MEMBER", + ) + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_set_role(self, async_client: AsyncGitpod) -> None: + response = await async_client.organizations.with_raw_response.set_role( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(object, organization, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_set_role(self, async_client: AsyncGitpod) -> None: + async with async_client.organizations.with_streaming_response.set_role( + organization_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(object, organization, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py new file mode 100644 index 0000000..217408d --- /dev/null +++ b/tests/api_resources/test_projects.py @@ -0,0 +1,581 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import ( + Project, + ProjectCreateResponse, + ProjectUpdateResponse, + ProjectRetrieveResponse, + ProjectCreateFromEnvironmentResponse, +) +from gitpod.pagination import SyncProjectsPage, AsyncProjectsPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestProjects: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + project = client.projects.create( + environment_class={}, + initializer={}, + ) + assert_matches_type(ProjectCreateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + project = client.projects.create( + environment_class={ + "environment_class_id": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "local_runner": True, + }, + initializer={ + "specs": [ + { + "context_url": {"url": "https://example.com"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "https://github.com/org/repo", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + automations_file_path="automationsFilePath", + devcontainer_file_path="devcontainerFilePath", + name="Web Application", + technical_description="technicalDescription", + ) + assert_matches_type(ProjectCreateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.projects.with_raw_response.create( + environment_class={}, + initializer={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(ProjectCreateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.projects.with_streaming_response.create( + environment_class={}, + initializer={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(ProjectCreateResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + project = client.projects.retrieve() + assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + project = client.projects.retrieve( + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.projects.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.projects.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + project = client.projects.update() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + project = client.projects.update( + automations_file_path="automationsFilePath", + devcontainer_file_path="devcontainerFilePath", + environment_class={ + "environment_class_id": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "local_runner": True, + }, + initializer={ + "specs": [ + { + "context_url": {"url": "https://example.com"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "remoteUri", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + name="x", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + technical_description="technicalDescription", + ) + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.projects.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.projects.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + project = client.projects.list() + assert_matches_type(SyncProjectsPage[Project], project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + project = client.projects.list( + token="token", + page_size=0, + filter={"project_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"]}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncProjectsPage[Project], project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.projects.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(SyncProjectsPage[Project], project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.projects.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(SyncProjectsPage[Project], project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + project = client.projects.delete() + assert_matches_type(object, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + project = client.projects.delete( + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(object, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.projects.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(object, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.projects.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(object, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_create_from_environment(self, client: Gitpod) -> None: + project = client.projects.create_from_environment() + assert_matches_type(ProjectCreateFromEnvironmentResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_from_environment_with_all_params(self, client: Gitpod) -> None: + project = client.projects.create_from_environment( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + name="Frontend Project", + ) + assert_matches_type(ProjectCreateFromEnvironmentResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create_from_environment(self, client: Gitpod) -> None: + response = client.projects.with_raw_response.create_from_environment() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(ProjectCreateFromEnvironmentResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create_from_environment(self, client: Gitpod) -> None: + with client.projects.with_streaming_response.create_from_environment() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(ProjectCreateFromEnvironmentResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncProjects: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.create( + environment_class={}, + initializer={}, + ) + assert_matches_type(ProjectCreateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.create( + environment_class={ + "environment_class_id": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "local_runner": True, + }, + initializer={ + "specs": [ + { + "context_url": {"url": "https://example.com"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "https://github.com/org/repo", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + automations_file_path="automationsFilePath", + devcontainer_file_path="devcontainerFilePath", + name="Web Application", + technical_description="technicalDescription", + ) + assert_matches_type(ProjectCreateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.with_raw_response.create( + environment_class={}, + initializer={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(ProjectCreateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.with_streaming_response.create( + environment_class={}, + initializer={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(ProjectCreateResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.retrieve() + assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.retrieve( + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.update() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.update( + automations_file_path="automationsFilePath", + devcontainer_file_path="devcontainerFilePath", + environment_class={ + "environment_class_id": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + "local_runner": True, + }, + initializer={ + "specs": [ + { + "context_url": {"url": "https://example.com"}, + "git": { + "checkout_location": "checkoutLocation", + "clone_target": "cloneTarget", + "remote_uri": "remoteUri", + "target_mode": "CLONE_TARGET_MODE_UNSPECIFIED", + "upstream_remote_uri": "upstreamRemoteUri", + }, + } + ] + }, + name="x", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + technical_description="technicalDescription", + ) + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.list() + assert_matches_type(AsyncProjectsPage[Project], project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.list( + token="token", + page_size=0, + filter={"project_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"]}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncProjectsPage[Project], project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(AsyncProjectsPage[Project], project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(AsyncProjectsPage[Project], project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.delete() + assert_matches_type(object, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.delete( + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + ) + assert_matches_type(object, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(object, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(object, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_create_from_environment(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.create_from_environment() + assert_matches_type(ProjectCreateFromEnvironmentResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_from_environment_with_all_params(self, async_client: AsyncGitpod) -> None: + project = await async_client.projects.create_from_environment( + environment_id="07e03a28-65a5-4d98-b532-8ea67b188048", + name="Frontend Project", + ) + assert_matches_type(ProjectCreateFromEnvironmentResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create_from_environment(self, async_client: AsyncGitpod) -> None: + response = await async_client.projects.with_raw_response.create_from_environment() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(ProjectCreateFromEnvironmentResponse, project, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create_from_environment(self, async_client: AsyncGitpod) -> None: + async with async_client.projects.with_streaming_response.create_from_environment() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(ProjectCreateFromEnvironmentResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_runners.py b/tests/api_resources/test_runners.py new file mode 100644 index 0000000..5fc76d7 --- /dev/null +++ b/tests/api_resources/test_runners.py @@ -0,0 +1,704 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import ( + Runner, + RunnerCreateResponse, + RunnerRetrieveResponse, + RunnerParseContextURLResponse, + RunnerCreateRunnerTokenResponse, + RunnerCheckAuthenticationForHostResponse, +) +from gitpod.pagination import SyncRunnersPage, AsyncRunnersPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRunners: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + runner = client.runners.create() + assert_matches_type(RunnerCreateResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + runner = client.runners.create( + kind="RUNNER_KIND_UNSPECIFIED", + name="Production Runner", + provider="RUNNER_PROVIDER_AWS_EC2", + runner_manager_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + spec={ + "configuration": { + "auto_update": True, + "devcontainer_image_cache_enabled": True, + "log_level": "LOG_LEVEL_UNSPECIFIED", + "metrics": { + "enabled": True, + "password": "password", + "url": "url", + "username": "username", + }, + "region": "us-west", + "release_channel": "RUNNER_RELEASE_CHANNEL_STABLE", + }, + "desired_phase": "RUNNER_PHASE_ACTIVE", + }, + ) + assert_matches_type(RunnerCreateResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.runners.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = response.parse() + assert_matches_type(RunnerCreateResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.runners.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = response.parse() + assert_matches_type(RunnerCreateResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Gitpod) -> None: + runner = client.runners.retrieve() + assert_matches_type(RunnerRetrieveResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_retrieve_with_all_params(self, client: Gitpod) -> None: + runner = client.runners.retrieve( + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(RunnerRetrieveResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Gitpod) -> None: + response = client.runners.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = response.parse() + assert_matches_type(RunnerRetrieveResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Gitpod) -> None: + with client.runners.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = response.parse() + assert_matches_type(RunnerRetrieveResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update(self, client: Gitpod) -> None: + runner = client.runners.update() + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_with_all_params(self, client: Gitpod) -> None: + runner = client.runners.update( + name="Updated Runner Name", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + spec={ + "configuration": { + "auto_update": True, + "devcontainer_image_cache_enabled": True, + "log_level": "LOG_LEVEL_UNSPECIFIED", + "metrics": { + "enabled": True, + "password": "password", + "url": "url", + "username": "username", + }, + "release_channel": "RUNNER_RELEASE_CHANNEL_LATEST", + }, + "desired_phase": "RUNNER_PHASE_UNSPECIFIED", + }, + ) + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update(self, client: Gitpod) -> None: + response = client.runners.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = response.parse() + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update(self, client: Gitpod) -> None: + with client.runners.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = response.parse() + assert_matches_type(object, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + runner = client.runners.list() + assert_matches_type(SyncRunnersPage[Runner], runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + runner = client.runners.list( + token="token", + page_size=0, + filter={ + "creator_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "kinds": ["RUNNER_KIND_UNSPECIFIED"], + "providers": ["RUNNER_PROVIDER_AWS_EC2"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncRunnersPage[Runner], runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.runners.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = response.parse() + assert_matches_type(SyncRunnersPage[Runner], runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.runners.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = response.parse() + assert_matches_type(SyncRunnersPage[Runner], runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + runner = client.runners.delete() + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + runner = client.runners.delete( + force=True, + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.runners.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = response.parse() + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.runners.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = response.parse() + assert_matches_type(object, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_check_authentication_for_host(self, client: Gitpod) -> None: + runner = client.runners.check_authentication_for_host() + assert_matches_type(RunnerCheckAuthenticationForHostResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_check_authentication_for_host_with_all_params(self, client: Gitpod) -> None: + runner = client.runners.check_authentication_for_host( + host="github.com", + runner_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(RunnerCheckAuthenticationForHostResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_check_authentication_for_host(self, client: Gitpod) -> None: + response = client.runners.with_raw_response.check_authentication_for_host() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = response.parse() + assert_matches_type(RunnerCheckAuthenticationForHostResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_check_authentication_for_host(self, client: Gitpod) -> None: + with client.runners.with_streaming_response.check_authentication_for_host() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = response.parse() + assert_matches_type(RunnerCheckAuthenticationForHostResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_create_runner_token(self, client: Gitpod) -> None: + runner = client.runners.create_runner_token() + assert_matches_type(RunnerCreateRunnerTokenResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_runner_token_with_all_params(self, client: Gitpod) -> None: + runner = client.runners.create_runner_token( + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(RunnerCreateRunnerTokenResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create_runner_token(self, client: Gitpod) -> None: + response = client.runners.with_raw_response.create_runner_token() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = response.parse() + assert_matches_type(RunnerCreateRunnerTokenResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create_runner_token(self, client: Gitpod) -> None: + with client.runners.with_streaming_response.create_runner_token() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = response.parse() + assert_matches_type(RunnerCreateRunnerTokenResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_parse_context_url(self, client: Gitpod) -> None: + runner = client.runners.parse_context_url() + assert_matches_type(RunnerParseContextURLResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_parse_context_url_with_all_params(self, client: Gitpod) -> None: + runner = client.runners.parse_context_url( + context_url="https://github.com/org/repo/tree/main", + runner_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(RunnerParseContextURLResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_parse_context_url(self, client: Gitpod) -> None: + response = client.runners.with_raw_response.parse_context_url() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = response.parse() + assert_matches_type(RunnerParseContextURLResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_parse_context_url(self, client: Gitpod) -> None: + with client.runners.with_streaming_response.parse_context_url() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = response.parse() + assert_matches_type(RunnerParseContextURLResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRunners: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.create() + assert_matches_type(RunnerCreateResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.create( + kind="RUNNER_KIND_UNSPECIFIED", + name="Production Runner", + provider="RUNNER_PROVIDER_AWS_EC2", + runner_manager_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + spec={ + "configuration": { + "auto_update": True, + "devcontainer_image_cache_enabled": True, + "log_level": "LOG_LEVEL_UNSPECIFIED", + "metrics": { + "enabled": True, + "password": "password", + "url": "url", + "username": "username", + }, + "region": "us-west", + "release_channel": "RUNNER_RELEASE_CHANNEL_STABLE", + }, + "desired_phase": "RUNNER_PHASE_ACTIVE", + }, + ) + assert_matches_type(RunnerCreateResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = await response.parse() + assert_matches_type(RunnerCreateResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = await response.parse() + assert_matches_type(RunnerCreateResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.retrieve() + assert_matches_type(RunnerRetrieveResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.retrieve( + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(RunnerRetrieveResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = await response.parse() + assert_matches_type(RunnerRetrieveResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = await response.parse() + assert_matches_type(RunnerRetrieveResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.update() + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.update( + name="Updated Runner Name", + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + spec={ + "configuration": { + "auto_update": True, + "devcontainer_image_cache_enabled": True, + "log_level": "LOG_LEVEL_UNSPECIFIED", + "metrics": { + "enabled": True, + "password": "password", + "url": "url", + "username": "username", + }, + "release_channel": "RUNNER_RELEASE_CHANNEL_LATEST", + }, + "desired_phase": "RUNNER_PHASE_UNSPECIFIED", + }, + ) + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.with_raw_response.update() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = await response.parse() + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.with_streaming_response.update() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = await response.parse() + assert_matches_type(object, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.list() + assert_matches_type(AsyncRunnersPage[Runner], runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.list( + token="token", + page_size=0, + filter={ + "creator_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "kinds": ["RUNNER_KIND_UNSPECIFIED"], + "providers": ["RUNNER_PROVIDER_AWS_EC2"], + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncRunnersPage[Runner], runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = await response.parse() + assert_matches_type(AsyncRunnersPage[Runner], runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = await response.parse() + assert_matches_type(AsyncRunnersPage[Runner], runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.delete() + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.delete( + force=True, + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = await response.parse() + assert_matches_type(object, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = await response.parse() + assert_matches_type(object, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_check_authentication_for_host(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.check_authentication_for_host() + assert_matches_type(RunnerCheckAuthenticationForHostResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_check_authentication_for_host_with_all_params(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.check_authentication_for_host( + host="github.com", + runner_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(RunnerCheckAuthenticationForHostResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_check_authentication_for_host(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.with_raw_response.check_authentication_for_host() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = await response.parse() + assert_matches_type(RunnerCheckAuthenticationForHostResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_check_authentication_for_host(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.with_streaming_response.check_authentication_for_host() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = await response.parse() + assert_matches_type(RunnerCheckAuthenticationForHostResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_create_runner_token(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.create_runner_token() + assert_matches_type(RunnerCreateRunnerTokenResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_runner_token_with_all_params(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.create_runner_token( + runner_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(RunnerCreateRunnerTokenResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create_runner_token(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.with_raw_response.create_runner_token() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = await response.parse() + assert_matches_type(RunnerCreateRunnerTokenResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create_runner_token(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.with_streaming_response.create_runner_token() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = await response.parse() + assert_matches_type(RunnerCreateRunnerTokenResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_parse_context_url(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.parse_context_url() + assert_matches_type(RunnerParseContextURLResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_parse_context_url_with_all_params(self, async_client: AsyncGitpod) -> None: + runner = await async_client.runners.parse_context_url( + context_url="https://github.com/org/repo/tree/main", + runner_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(RunnerParseContextURLResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_parse_context_url(self, async_client: AsyncGitpod) -> None: + response = await async_client.runners.with_raw_response.parse_context_url() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + runner = await response.parse() + assert_matches_type(RunnerParseContextURLResponse, runner, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_parse_context_url(self, async_client: AsyncGitpod) -> None: + async with async_client.runners.with_streaming_response.parse_context_url() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + runner = await response.parse() + assert_matches_type(RunnerParseContextURLResponse, runner, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_secrets.py b/tests/api_resources/test_secrets.py new file mode 100644 index 0000000..1b215c5 --- /dev/null +++ b/tests/api_resources/test_secrets.py @@ -0,0 +1,433 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import ( + Secret, + SecretCreateResponse, + SecretGetValueResponse, +) +from gitpod.pagination import SyncSecretsPage, AsyncSecretsPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSecrets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Gitpod) -> None: + secret = client.secrets.create() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Gitpod) -> None: + secret = client.secrets.create( + container_registry_basic_auth_host="containerRegistryBasicAuthHost", + environment_variable=True, + file_path="filePath", + name="DATABASE_URL", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + scope={ + "project_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + }, + value="postgresql://user:pass@localhost:5432/db", + ) + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Gitpod) -> None: + response = client.secrets.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Gitpod) -> None: + with client.secrets.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + secret = client.secrets.list() + assert_matches_type(SyncSecretsPage[Secret], secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + secret = client.secrets.list( + token="token", + page_size=0, + filter={ + "project_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "scope": { + "project_id": "b0e12f6c-4c67-429d-a4a6-d9838b5da047", + "user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + }, + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncSecretsPage[Secret], secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.secrets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(SyncSecretsPage[Secret], secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.secrets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(SyncSecretsPage[Secret], secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + secret = client.secrets.delete() + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + secret = client.secrets.delete( + secret_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.secrets.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.secrets.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(object, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_get_value(self, client: Gitpod) -> None: + secret = client.secrets.get_value() + assert_matches_type(SecretGetValueResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_get_value_with_all_params(self, client: Gitpod) -> None: + secret = client.secrets.get_value( + secret_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(SecretGetValueResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_get_value(self, client: Gitpod) -> None: + response = client.secrets.with_raw_response.get_value() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(SecretGetValueResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_get_value(self, client: Gitpod) -> None: + with client.secrets.with_streaming_response.get_value() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(SecretGetValueResponse, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_update_value(self, client: Gitpod) -> None: + secret = client.secrets.update_value() + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_update_value_with_all_params(self, client: Gitpod) -> None: + secret = client.secrets.update_value( + secret_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + value="new-secret-value", + ) + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_update_value(self, client: Gitpod) -> None: + response = client.secrets.with_raw_response.update_value() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_update_value(self, client: Gitpod) -> None: + with client.secrets.with_streaming_response.update_value() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(object, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncSecrets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.create() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.create( + container_registry_basic_auth_host="containerRegistryBasicAuthHost", + environment_variable=True, + file_path="filePath", + name="DATABASE_URL", + project_id="b0e12f6c-4c67-429d-a4a6-d9838b5da047", + scope={ + "project_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + }, + value="postgresql://user:pass@localhost:5432/db", + ) + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncGitpod) -> None: + response = await async_client.secrets.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGitpod) -> None: + async with async_client.secrets.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.list() + assert_matches_type(AsyncSecretsPage[Secret], secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.list( + token="token", + page_size=0, + filter={ + "project_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "scope": { + "project_id": "b0e12f6c-4c67-429d-a4a6-d9838b5da047", + "user_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + }, + }, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncSecretsPage[Secret], secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.secrets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(AsyncSecretsPage[Secret], secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.secrets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(AsyncSecretsPage[Secret], secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.delete() + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.delete( + secret_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.secrets.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.secrets.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(object, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_get_value(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.get_value() + assert_matches_type(SecretGetValueResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_get_value_with_all_params(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.get_value( + secret_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(SecretGetValueResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_get_value(self, async_client: AsyncGitpod) -> None: + response = await async_client.secrets.with_raw_response.get_value() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(SecretGetValueResponse, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_get_value(self, async_client: AsyncGitpod) -> None: + async with async_client.secrets.with_streaming_response.get_value() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(SecretGetValueResponse, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_update_value(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.update_value() + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_update_value_with_all_params(self, async_client: AsyncGitpod) -> None: + secret = await async_client.secrets.update_value( + secret_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + value="new-secret-value", + ) + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_update_value(self, async_client: AsyncGitpod) -> None: + response = await async_client.secrets.with_raw_response.update_value() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(object, secret, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_update_value(self, async_client: AsyncGitpod) -> None: + async with async_client.secrets.with_streaming_response.update_value() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(object, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_usage.py b/tests/api_resources/test_usage.py new file mode 100644 index 0000000..e92f8ae --- /dev/null +++ b/tests/api_resources/test_usage.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import EnvironmentUsageRecord +from gitpod._utils import parse_datetime +from gitpod.pagination import SyncRecordsPage, AsyncRecordsPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsage: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_environment_runtime_records(self, client: Gitpod) -> None: + usage = client.usage.list_environment_runtime_records() + assert_matches_type(SyncRecordsPage[EnvironmentUsageRecord], usage, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_environment_runtime_records_with_all_params(self, client: Gitpod) -> None: + usage = client.usage.list_environment_runtime_records( + token="token", + page_size=0, + filter={ + "date_range": { + "end_time": parse_datetime("2024-01-02T00:00:00Z"), + "start_time": parse_datetime("2024-01-01T00:00:00Z"), + }, + "project_id": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + }, + pagination={ + "token": "token", + "page_size": 100, + }, + ) + assert_matches_type(SyncRecordsPage[EnvironmentUsageRecord], usage, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list_environment_runtime_records(self, client: Gitpod) -> None: + response = client.usage.with_raw_response.list_environment_runtime_records() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(SyncRecordsPage[EnvironmentUsageRecord], usage, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list_environment_runtime_records(self, client: Gitpod) -> None: + with client.usage.with_streaming_response.list_environment_runtime_records() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(SyncRecordsPage[EnvironmentUsageRecord], usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncUsage: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_list_environment_runtime_records(self, async_client: AsyncGitpod) -> None: + usage = await async_client.usage.list_environment_runtime_records() + assert_matches_type(AsyncRecordsPage[EnvironmentUsageRecord], usage, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_environment_runtime_records_with_all_params(self, async_client: AsyncGitpod) -> None: + usage = await async_client.usage.list_environment_runtime_records( + token="token", + page_size=0, + filter={ + "date_range": { + "end_time": parse_datetime("2024-01-02T00:00:00Z"), + "start_time": parse_datetime("2024-01-01T00:00:00Z"), + }, + "project_id": "d2c94c27-3b76-4a42-b88c-95a85e392c68", + }, + pagination={ + "token": "token", + "page_size": 100, + }, + ) + assert_matches_type(AsyncRecordsPage[EnvironmentUsageRecord], usage, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list_environment_runtime_records(self, async_client: AsyncGitpod) -> None: + response = await async_client.usage.with_raw_response.list_environment_runtime_records() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = await response.parse() + assert_matches_type(AsyncRecordsPage[EnvironmentUsageRecord], usage, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list_environment_runtime_records(self, async_client: AsyncGitpod) -> None: + async with async_client.usage.with_streaming_response.list_environment_runtime_records() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(AsyncRecordsPage[EnvironmentUsageRecord], usage, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_users.py b/tests/api_resources/test_users.py new file mode 100644 index 0000000..2c16986 --- /dev/null +++ b/tests/api_resources/test_users.py @@ -0,0 +1,170 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types import UserGetAuthenticatedUserResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_get_authenticated_user(self, client: Gitpod) -> None: + user = client.users.get_authenticated_user() + assert_matches_type(UserGetAuthenticatedUserResponse, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_get_authenticated_user_with_all_params(self, client: Gitpod) -> None: + user = client.users.get_authenticated_user( + empty=True, + ) + assert_matches_type(UserGetAuthenticatedUserResponse, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_get_authenticated_user(self, client: Gitpod) -> None: + response = client.users.with_raw_response.get_authenticated_user() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserGetAuthenticatedUserResponse, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_get_authenticated_user(self, client: Gitpod) -> None: + with client.users.with_streaming_response.get_authenticated_user() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserGetAuthenticatedUserResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_set_suspended(self, client: Gitpod) -> None: + user = client.users.set_suspended() + assert_matches_type(object, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_set_suspended_with_all_params(self, client: Gitpod) -> None: + user = client.users.set_suspended( + suspended=False, + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(object, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_set_suspended(self, client: Gitpod) -> None: + response = client.users.with_raw_response.set_suspended() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(object, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_set_suspended(self, client: Gitpod) -> None: + with client.users.with_streaming_response.set_suspended() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(object, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncUsers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_get_authenticated_user(self, async_client: AsyncGitpod) -> None: + user = await async_client.users.get_authenticated_user() + assert_matches_type(UserGetAuthenticatedUserResponse, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_get_authenticated_user_with_all_params(self, async_client: AsyncGitpod) -> None: + user = await async_client.users.get_authenticated_user( + empty=True, + ) + assert_matches_type(UserGetAuthenticatedUserResponse, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_get_authenticated_user(self, async_client: AsyncGitpod) -> None: + response = await async_client.users.with_raw_response.get_authenticated_user() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(UserGetAuthenticatedUserResponse, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_get_authenticated_user(self, async_client: AsyncGitpod) -> None: + async with async_client.users.with_streaming_response.get_authenticated_user() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserGetAuthenticatedUserResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_set_suspended(self, async_client: AsyncGitpod) -> None: + user = await async_client.users.set_suspended() + assert_matches_type(object, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_set_suspended_with_all_params(self, async_client: AsyncGitpod) -> None: + user = await async_client.users.set_suspended( + suspended=False, + user_id="f53d2330-3795-4c5d-a1f3-453121af9c60", + ) + assert_matches_type(object, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_set_suspended(self, async_client: AsyncGitpod) -> None: + response = await async_client.users.with_raw_response.set_suspended() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(object, user, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_set_suspended(self, async_client: AsyncGitpod) -> None: + async with async_client.users.with_streaming_response.set_suspended() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(object, user, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/users/__init__.py b/tests/api_resources/users/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/users/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/users/test_dotfiles.py b/tests/api_resources/users/test_dotfiles.py new file mode 100644 index 0000000..1bb65b7 --- /dev/null +++ b/tests/api_resources/users/test_dotfiles.py @@ -0,0 +1,168 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.types.users import DotfileGetResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDotfiles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_get(self, client: Gitpod) -> None: + dotfile = client.users.dotfiles.get() + assert_matches_type(DotfileGetResponse, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_get_with_all_params(self, client: Gitpod) -> None: + dotfile = client.users.dotfiles.get( + empty=True, + ) + assert_matches_type(DotfileGetResponse, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_get(self, client: Gitpod) -> None: + response = client.users.dotfiles.with_raw_response.get() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dotfile = response.parse() + assert_matches_type(DotfileGetResponse, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_get(self, client: Gitpod) -> None: + with client.users.dotfiles.with_streaming_response.get() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dotfile = response.parse() + assert_matches_type(DotfileGetResponse, dotfile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_set(self, client: Gitpod) -> None: + dotfile = client.users.dotfiles.set() + assert_matches_type(object, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_set_with_all_params(self, client: Gitpod) -> None: + dotfile = client.users.dotfiles.set( + repository="https://example.com", + ) + assert_matches_type(object, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_set(self, client: Gitpod) -> None: + response = client.users.dotfiles.with_raw_response.set() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dotfile = response.parse() + assert_matches_type(object, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_set(self, client: Gitpod) -> None: + with client.users.dotfiles.with_streaming_response.set() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dotfile = response.parse() + assert_matches_type(object, dotfile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncDotfiles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_get(self, async_client: AsyncGitpod) -> None: + dotfile = await async_client.users.dotfiles.get() + assert_matches_type(DotfileGetResponse, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncGitpod) -> None: + dotfile = await async_client.users.dotfiles.get( + empty=True, + ) + assert_matches_type(DotfileGetResponse, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_get(self, async_client: AsyncGitpod) -> None: + response = await async_client.users.dotfiles.with_raw_response.get() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dotfile = await response.parse() + assert_matches_type(DotfileGetResponse, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGitpod) -> None: + async with async_client.users.dotfiles.with_streaming_response.get() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dotfile = await response.parse() + assert_matches_type(DotfileGetResponse, dotfile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_set(self, async_client: AsyncGitpod) -> None: + dotfile = await async_client.users.dotfiles.set() + assert_matches_type(object, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_set_with_all_params(self, async_client: AsyncGitpod) -> None: + dotfile = await async_client.users.dotfiles.set( + repository="https://example.com", + ) + assert_matches_type(object, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_set(self, async_client: AsyncGitpod) -> None: + response = await async_client.users.dotfiles.with_raw_response.set() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dotfile = await response.parse() + assert_matches_type(object, dotfile, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_set(self, async_client: AsyncGitpod) -> None: + async with async_client.users.dotfiles.with_streaming_response.set() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dotfile = await response.parse() + assert_matches_type(object, dotfile, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/users/test_pats.py b/tests/api_resources/users/test_pats.py new file mode 100644 index 0000000..c8e1082 --- /dev/null +++ b/tests/api_resources/users/test_pats.py @@ -0,0 +1,253 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gitpod import Gitpod, AsyncGitpod +from tests.utils import assert_matches_type +from gitpod.pagination import SyncPersonalAccessTokensPage, AsyncPersonalAccessTokensPage +from gitpod.types.users import PatGetResponse, PersonalAccessToken + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPats: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Gitpod) -> None: + pat = client.users.pats.list() + assert_matches_type(SyncPersonalAccessTokensPage[PersonalAccessToken], pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Gitpod) -> None: + pat = client.users.pats.list( + token="token", + page_size=0, + filter={"user_ids": ["f53d2330-3795-4c5d-a1f3-453121af9c60"]}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(SyncPersonalAccessTokensPage[PersonalAccessToken], pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Gitpod) -> None: + response = client.users.pats.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pat = response.parse() + assert_matches_type(SyncPersonalAccessTokensPage[PersonalAccessToken], pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Gitpod) -> None: + with client.users.pats.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pat = response.parse() + assert_matches_type(SyncPersonalAccessTokensPage[PersonalAccessToken], pat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_delete(self, client: Gitpod) -> None: + pat = client.users.pats.delete() + assert_matches_type(object, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_delete_with_all_params(self, client: Gitpod) -> None: + pat = client.users.pats.delete( + personal_access_token_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_delete(self, client: Gitpod) -> None: + response = client.users.pats.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pat = response.parse() + assert_matches_type(object, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_delete(self, client: Gitpod) -> None: + with client.users.pats.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pat = response.parse() + assert_matches_type(object, pat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_get(self, client: Gitpod) -> None: + pat = client.users.pats.get() + assert_matches_type(PatGetResponse, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_get_with_all_params(self, client: Gitpod) -> None: + pat = client.users.pats.get( + personal_access_token_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(PatGetResponse, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_get(self, client: Gitpod) -> None: + response = client.users.pats.with_raw_response.get() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pat = response.parse() + assert_matches_type(PatGetResponse, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_get(self, client: Gitpod) -> None: + with client.users.pats.with_streaming_response.get() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pat = response.parse() + assert_matches_type(PatGetResponse, pat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPats: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncGitpod) -> None: + pat = await async_client.users.pats.list() + assert_matches_type(AsyncPersonalAccessTokensPage[PersonalAccessToken], pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGitpod) -> None: + pat = await async_client.users.pats.list( + token="token", + page_size=0, + filter={"user_ids": ["f53d2330-3795-4c5d-a1f3-453121af9c60"]}, + pagination={ + "token": "token", + "page_size": 20, + }, + ) + assert_matches_type(AsyncPersonalAccessTokensPage[PersonalAccessToken], pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncGitpod) -> None: + response = await async_client.users.pats.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pat = await response.parse() + assert_matches_type(AsyncPersonalAccessTokensPage[PersonalAccessToken], pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGitpod) -> None: + async with async_client.users.pats.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pat = await response.parse() + assert_matches_type(AsyncPersonalAccessTokensPage[PersonalAccessToken], pat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_delete(self, async_client: AsyncGitpod) -> None: + pat = await async_client.users.pats.delete() + assert_matches_type(object, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGitpod) -> None: + pat = await async_client.users.pats.delete( + personal_access_token_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(object, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGitpod) -> None: + response = await async_client.users.pats.with_raw_response.delete() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pat = await response.parse() + assert_matches_type(object, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGitpod) -> None: + async with async_client.users.pats.with_streaming_response.delete() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pat = await response.parse() + assert_matches_type(object, pat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_get(self, async_client: AsyncGitpod) -> None: + pat = await async_client.users.pats.get() + assert_matches_type(PatGetResponse, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncGitpod) -> None: + pat = await async_client.users.pats.get( + personal_access_token_id="d2c94c27-3b76-4a42-b88c-95a85e392c68", + ) + assert_matches_type(PatGetResponse, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_get(self, async_client: AsyncGitpod) -> None: + response = await async_client.users.pats.with_raw_response.get() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pat = await response.parse() + assert_matches_type(PatGetResponse, pat, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGitpod) -> None: + async with async_client.users.pats.with_streaming_response.get() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pat = await response.parse() + assert_matches_type(PatGetResponse, pat, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..8697828 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,84 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +import logging +from typing import TYPE_CHECKING, Iterator, AsyncIterator + +import httpx +import pytest +from pytest_asyncio import is_async_test + +from gitpod import Gitpod, AsyncGitpod, DefaultAioHttpClient +from gitpod._utils import is_dict + +if TYPE_CHECKING: + from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] + +pytest.register_assert_rewrite("tests.utils") + +logging.getLogger("gitpod").setLevel(logging.DEBUG) + + +# automatically add `pytest.mark.asyncio()` to all of our async tests +# so we don't have to add that boilerplate everywhere +def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: + pytest_asyncio_tests = (item for item in items if is_async_test(item)) + session_scope_marker = pytest.mark.asyncio(loop_scope="session") + for async_test in pytest_asyncio_tests: + async_test.add_marker(session_scope_marker, append=False) + + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + async_client_param = item.callspec.params.get("async_client") + if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": + item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) + + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + +bearer_token = "My Bearer Token" + + +@pytest.fixture(scope="session") +def client(request: FixtureRequest) -> Iterator[Gitpod]: + strict = getattr(request, "param", True) + if not isinstance(strict, bool): + raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") + + with Gitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=strict) as client: + yield client + + +@pytest.fixture(scope="session") +async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncGitpod]: + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") + + async with AsyncGitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=strict, http_client=http_client + ) as client: + yield client diff --git a/tests/decoders/test_jsonl.py b/tests/decoders/test_jsonl.py new file mode 100644 index 0000000..a14a93e --- /dev/null +++ b/tests/decoders/test_jsonl.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from typing import Any, Iterator, AsyncIterator +from typing_extensions import TypeVar + +import httpx +import pytest + +from gitpod._decoders.jsonl import JSONLDecoder, AsyncJSONLDecoder + +_T = TypeVar("_T") + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_basic(sync: bool) -> None: + def body() -> Iterator[bytes]: + yield b'{"foo":true}\n' + yield b'{"bar":false}\n' + + iterator = make_jsonl_iterator( + content=body(), + sync=sync, + line_type=object, + ) + + assert await iter_next(iterator) == {"foo": True} + assert await iter_next(iterator) == {"bar": False} + + await assert_empty_iter(iterator) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_new_lines_in_json( + sync: bool, +) -> None: + def body() -> Iterator[bytes]: + yield b'{"content":"Hello, world!\\nHow are you doing?"}' + + iterator = make_jsonl_iterator(content=body(), sync=sync, line_type=object) + + assert await iter_next(iterator) == {"content": "Hello, world!\nHow are you doing?"} + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multi_byte_character_multiple_chunks( + sync: bool, +) -> None: + def body() -> Iterator[bytes]: + yield b'{"content":"' + # bytes taken from the string 'известни' and arbitrarily split + # so that some multi-byte characters span multiple chunks + yield b"\xd0" + yield b"\xb8\xd0\xb7\xd0" + yield b"\xb2\xd0\xb5\xd1\x81\xd1\x82\xd0\xbd\xd0\xb8" + yield b'"}\n' + + iterator = make_jsonl_iterator(content=body(), sync=sync, line_type=object) + + assert await iter_next(iterator) == {"content": "известни"} + + +async def to_aiter(iter: Iterator[bytes]) -> AsyncIterator[bytes]: + for chunk in iter: + yield chunk + + +async def iter_next(iter: Iterator[_T] | AsyncIterator[_T]) -> _T: + if isinstance(iter, AsyncIterator): + return await iter.__anext__() + return next(iter) + + +async def assert_empty_iter(decoder: JSONLDecoder[Any] | AsyncJSONLDecoder[Any]) -> None: + with pytest.raises((StopAsyncIteration, RuntimeError)): + await iter_next(decoder) + + +def make_jsonl_iterator( + content: Iterator[bytes], + *, + sync: bool, + line_type: type[_T], +) -> JSONLDecoder[_T] | AsyncJSONLDecoder[_T]: + if sync: + return JSONLDecoder(line_type=line_type, raw_iterator=content, http_response=httpx.Response(200)) + + return AsyncJSONLDecoder(line_type=line_type, raw_iterator=to_aiter(content), http_response=httpx.Response(200)) diff --git a/tests/sample_file.txt b/tests/sample_file.txt new file mode 100644 index 0000000..af5626b --- /dev/null +++ b/tests/sample_file.txt @@ -0,0 +1 @@ +Hello, world! diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 0000000..1c80f7b --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,1778 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import gc +import os +import sys +import json +import time +import asyncio +import inspect +import subprocess +import tracemalloc +from typing import Any, Union, cast +from textwrap import dedent +from unittest import mock +from typing_extensions import Literal + +import httpx +import pytest +from respx import MockRouter +from pydantic import ValidationError + +from gitpod import Gitpod, AsyncGitpod, APIResponseValidationError +from gitpod._types import Omit +from gitpod._models import BaseModel, FinalRequestOptions +from gitpod._exceptions import GitpodError, APIStatusError, APITimeoutError, APIResponseValidationError +from gitpod._base_client import ( + DEFAULT_TIMEOUT, + HTTPX_DEFAULT_TIMEOUT, + BaseClient, + DefaultHttpxClient, + DefaultAsyncHttpxClient, + make_request_options, +) + +from .utils import update_env + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") +bearer_token = "My Bearer Token" + + +def _get_params(client: BaseClient[Any, Any]) -> dict[str, str]: + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + url = httpx.URL(request.url) + return dict(url.params) + + +def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float: + return 0.1 + + +def _get_open_connections(client: Gitpod | AsyncGitpod) -> int: + transport = client._client._transport + assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport) + + pool = transport._pool + return len(pool._requests) + + +class TestGitpod: + client = Gitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + + @pytest.mark.respx(base_url=base_url) + def test_raw_response(self, respx_mock: MockRouter) -> None: + respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = self.client.post("/foo", cast_to=httpx.Response) + assert response.status_code == 200 + assert isinstance(response, httpx.Response) + assert response.json() == {"foo": "bar"} + + @pytest.mark.respx(base_url=base_url) + def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + respx_mock.post("/foo").mock( + return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') + ) + + response = self.client.post("/foo", cast_to=httpx.Response) + assert response.status_code == 200 + assert isinstance(response, httpx.Response) + assert response.json() == {"foo": "bar"} + + def test_copy(self) -> None: + copied = self.client.copy() + assert id(copied) != id(self.client) + + copied = self.client.copy(bearer_token="another My Bearer Token") + assert copied.bearer_token == "another My Bearer Token" + assert self.client.bearer_token == "My Bearer Token" + + def test_copy_default_options(self) -> None: + # options that have a default are overridden correctly + copied = self.client.copy(max_retries=7) + assert copied.max_retries == 7 + assert self.client.max_retries == 2 + + copied2 = copied.copy(max_retries=6) + assert copied2.max_retries == 6 + assert copied.max_retries == 7 + + # timeout + assert isinstance(self.client.timeout, httpx.Timeout) + copied = self.client.copy(timeout=None) + assert copied.timeout is None + assert isinstance(self.client.timeout, httpx.Timeout) + + def test_copy_default_headers(self) -> None: + client = Gitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + default_headers={"X-Foo": "bar"}, + ) + assert client.default_headers["X-Foo"] == "bar" + + # does not override the already given value when not specified + copied = client.copy() + assert copied.default_headers["X-Foo"] == "bar" + + # merges already given headers + copied = client.copy(default_headers={"X-Bar": "stainless"}) + assert copied.default_headers["X-Foo"] == "bar" + assert copied.default_headers["X-Bar"] == "stainless" + + # uses new values for any already given headers + copied = client.copy(default_headers={"X-Foo": "stainless"}) + assert copied.default_headers["X-Foo"] == "stainless" + + # set_default_headers + + # completely overrides already set values + copied = client.copy(set_default_headers={}) + assert copied.default_headers.get("X-Foo") is None + + copied = client.copy(set_default_headers={"X-Bar": "Robert"}) + assert copied.default_headers["X-Bar"] == "Robert" + + with pytest.raises( + ValueError, + match="`default_headers` and `set_default_headers` arguments are mutually exclusive", + ): + client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + + def test_copy_default_query(self) -> None: + client = Gitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, default_query={"foo": "bar"} + ) + assert _get_params(client)["foo"] == "bar" + + # does not override the already given value when not specified + copied = client.copy() + assert _get_params(copied)["foo"] == "bar" + + # merges already given params + copied = client.copy(default_query={"bar": "stainless"}) + params = _get_params(copied) + assert params["foo"] == "bar" + assert params["bar"] == "stainless" + + # uses new values for any already given headers + copied = client.copy(default_query={"foo": "stainless"}) + assert _get_params(copied)["foo"] == "stainless" + + # set_default_query + + # completely overrides already set values + copied = client.copy(set_default_query={}) + assert _get_params(copied) == {} + + copied = client.copy(set_default_query={"bar": "Robert"}) + assert _get_params(copied)["bar"] == "Robert" + + with pytest.raises( + ValueError, + # TODO: update + match="`default_query` and `set_default_query` arguments are mutually exclusive", + ): + client.copy(set_default_query={}, default_query={"foo": "Bar"}) + + def test_copy_signature(self) -> None: + # ensure the same parameters that can be passed to the client are defined in the `.copy()` method + init_signature = inspect.signature( + # mypy doesn't like that we access the `__init__` property. + self.client.__init__, # type: ignore[misc] + ) + copy_signature = inspect.signature(self.client.copy) + exclude_params = {"transport", "proxies", "_strict_response_validation"} + + for name in init_signature.parameters.keys(): + if name in exclude_params: + continue + + copy_param = copy_signature.parameters.get(name) + assert copy_param is not None, f"copy() signature is missing the {name} param" + + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") + def test_copy_build_request(self) -> None: + options = FinalRequestOptions(method="get", url="/foo") + + def build_request(options: FinalRequestOptions) -> None: + client = self.client.copy() + client._build_request(options) + + # ensure that the machinery is warmed up before tracing starts. + build_request(options) + gc.collect() + + tracemalloc.start(1000) + + snapshot_before = tracemalloc.take_snapshot() + + ITERATIONS = 10 + for _ in range(ITERATIONS): + build_request(options) + + gc.collect() + snapshot_after = tracemalloc.take_snapshot() + + tracemalloc.stop() + + def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.StatisticDiff) -> None: + if diff.count == 0: + # Avoid false positives by considering only leaks (i.e. allocations that persist). + return + + if diff.count % ITERATIONS != 0: + # Avoid false positives by considering only leaks that appear per iteration. + return + + for frame in diff.traceback: + if any( + frame.filename.endswith(fragment) + for fragment in [ + # to_raw_response_wrapper leaks through the @functools.wraps() decorator. + # + # removing the decorator fixes the leak for reasons we don't understand. + "gitpod/_legacy_response.py", + "gitpod/_response.py", + # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason. + "gitpod/_compat.py", + # Standard library leaks we don't care about. + "/logging/__init__.py", + ] + ): + return + + leaks.append(diff) + + leaks: list[tracemalloc.StatisticDiff] = [] + for diff in snapshot_after.compare_to(snapshot_before, "traceback"): + add_leak(leaks, diff) + if leaks: + for leak in leaks: + print("MEMORY LEAK:", leak) + for frame in leak.traceback: + print(frame) + raise AssertionError() + + def test_request_timeout(self) -> None: + request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT + + request = self.client._build_request( + FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) + ) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(100.0) + + def test_client_timeout_option(self) -> None: + client = Gitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, timeout=httpx.Timeout(0) + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(0) + + def test_http_client_timeout_option(self) -> None: + # custom timeout given to the httpx client should be used + with httpx.Client(timeout=None) as http_client: + client = Gitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(None) + + # no timeout given to the httpx client should not use the httpx default + with httpx.Client() as http_client: + client = Gitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT + + # explicitly passing the default timeout currently results in it being ignored + with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: + client = Gitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT # our default + + async def test_invalid_http_client(self) -> None: + with pytest.raises(TypeError, match="Invalid `http_client` arg"): + async with httpx.AsyncClient() as http_client: + Gitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + http_client=cast(Any, http_client), + ) + + def test_default_headers_option(self) -> None: + client = Gitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + default_headers={"X-Foo": "bar"}, + ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "bar" + assert request.headers.get("x-stainless-lang") == "python" + + client2 = Gitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + default_headers={ + "X-Foo": "stainless", + "X-Stainless-Lang": "my-overriding-header", + }, + ) + request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "stainless" + assert request.headers.get("x-stainless-lang") == "my-overriding-header" + + def test_validate_headers(self) -> None: + client = Gitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("Authorization") == f"Bearer {bearer_token}" + + with pytest.raises(GitpodError): + with update_env(**{"GITPOD_API_KEY": Omit()}): + client2 = Gitpod(base_url=base_url, bearer_token=None, _strict_response_validation=True) + _ = client2 + + def test_default_query_option(self) -> None: + client = Gitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + default_query={"query_param": "bar"}, + ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + url = httpx.URL(request.url) + assert dict(url.params) == {"query_param": "bar"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/foo", + params={"foo": "baz", "query_param": "overridden"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} + + def test_request_extra_json(self) -> None: + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + extra_json={"baz": False}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"foo": "bar", "baz": False} + + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + extra_json={"baz": False}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"baz": False} + + # `extra_json` takes priority over `json_data` when keys clash + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar", "baz": True}, + extra_json={"baz": None}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"foo": "bar", "baz": None} + + def test_request_extra_headers(self) -> None: + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options(extra_headers={"X-Foo": "Foo"}), + ), + ) + assert request.headers.get("X-Foo") == "Foo" + + # `extra_headers` takes priority over `default_headers` when keys clash + request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + extra_headers={"X-Bar": "false"}, + ), + ), + ) + assert request.headers.get("X-Bar") == "false" + + def test_request_extra_query(self) -> None: + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + extra_query={"my_query_param": "Foo"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"my_query_param": "Foo"} + + # if both `query` and `extra_query` are given, they are merged + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + query={"bar": "1"}, + extra_query={"foo": "2"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"bar": "1", "foo": "2"} + + # `extra_query` takes priority over `query` when keys clash + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + query={"foo": "1"}, + extra_query={"foo": "2"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"foo": "2"} + + def test_multipart_repeating_array(self, client: Gitpod) -> None: + request = client._build_request( + FinalRequestOptions.construct( + method="post", + url="/foo", + headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, + json_data={"array": ["foo", "bar"]}, + files=[("foo.txt", b"hello world")], + ) + ) + + assert request.read().split(b"\r\n") == [ + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="array[]"', + b"", + b"foo", + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="array[]"', + b"", + b"bar", + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="foo.txt"; filename="upload"', + b"Content-Type: application/octet-stream", + b"", + b"hello world", + b"--6b7ba517decee4a450543ea6ae821c82--", + b"", + ] + + @pytest.mark.respx(base_url=base_url) + def test_basic_union_response(self, respx_mock: MockRouter) -> None: + class Model1(BaseModel): + name: str + + class Model2(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model2) + assert response.foo == "bar" + + @pytest.mark.respx(base_url=base_url) + def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + """Union of objects with the same field name using a different type""" + + class Model1(BaseModel): + foo: int + + class Model2(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model2) + assert response.foo == "bar" + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) + + response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model1) + assert response.foo == 1 + + @pytest.mark.respx(base_url=base_url) + def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + """ + Response that sets Content-Type to something other than application/json but returns json data + """ + + class Model(BaseModel): + foo: int + + respx_mock.get("/foo").mock( + return_value=httpx.Response( + 200, + content=json.dumps({"foo": 2}), + headers={"Content-Type": "application/text"}, + ) + ) + + response = self.client.get("/foo", cast_to=Model) + assert isinstance(response, Model) + assert response.foo == 2 + + def test_base_url_setter(self) -> None: + client = Gitpod( + base_url="https://example.com/from_init", bearer_token=bearer_token, _strict_response_validation=True + ) + assert client.base_url == "https://example.com/from_init/" + + client.base_url = "https://example.com/from_setter" # type: ignore[assignment] + + assert client.base_url == "https://example.com/from_setter/" + + def test_base_url_env(self) -> None: + with update_env(GITPOD_BASE_URL="http://localhost:5000/from/env"): + client = Gitpod(bearer_token=bearer_token, _strict_response_validation=True) + assert client.base_url == "http://localhost:5000/from/env/" + + @pytest.mark.parametrize( + "client", + [ + Gitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + ), + Gitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + http_client=httpx.Client(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_base_url_trailing_slash(self, client: Gitpod) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "http://localhost:5000/custom/path/foo" + + @pytest.mark.parametrize( + "client", + [ + Gitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + ), + Gitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + http_client=httpx.Client(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_base_url_no_trailing_slash(self, client: Gitpod) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "http://localhost:5000/custom/path/foo" + + @pytest.mark.parametrize( + "client", + [ + Gitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + ), + Gitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + http_client=httpx.Client(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_absolute_request_url(self, client: Gitpod) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="https://myapi.com/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "https://myapi.com/foo" + + def test_copied_client_does_not_close_http(self) -> None: + client = Gitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + assert not client.is_closed() + + copied = client.copy() + assert copied is not client + + del copied + + assert not client.is_closed() + + def test_client_context_manager(self) -> None: + client = Gitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + with client as c2: + assert c2 is client + assert not c2.is_closed() + assert not client.is_closed() + assert client.is_closed() + + @pytest.mark.respx(base_url=base_url) + def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + class Model(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) + + with pytest.raises(APIResponseValidationError) as exc: + self.client.get("/foo", cast_to=Model) + + assert isinstance(exc.value.__cause__, ValidationError) + + def test_client_max_retries_validation(self) -> None: + with pytest.raises(TypeError, match=r"max_retries cannot be None"): + Gitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + max_retries=cast(Any, None), + ) + + @pytest.mark.respx(base_url=base_url) + def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: + class Model(BaseModel): + name: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format")) + + strict_client = Gitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + + with pytest.raises(APIResponseValidationError): + strict_client.get("/foo", cast_to=Model) + + client = Gitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=False) + + response = client.get("/foo", cast_to=Model) + assert isinstance(response, str) # type: ignore[unreachable] + + @pytest.mark.parametrize( + "remaining_retries,retry_after,timeout", + [ + [3, "20", 20], + [3, "0", 0.5], + [3, "-10", 0.5], + [3, "60", 60], + [3, "61", 0.5], + [3, "Fri, 29 Sep 2023 16:26:57 GMT", 20], + [3, "Fri, 29 Sep 2023 16:26:37 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:27:37 GMT", 60], + [3, "Fri, 29 Sep 2023 16:27:38 GMT", 0.5], + [3, "99999999999999999999999999999999999", 0.5], + [3, "Zun, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "", 0.5], + [2, "", 0.5 * 2.0], + [1, "", 0.5 * 4.0], + [-1100, "", 8], # test large number potentially overflowing + ], + ) + @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) + def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: + client = Gitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + + headers = httpx.Headers({"retry-after": retry_after}) + options = FinalRequestOptions(method="get", url="/foo", max_retries=3) + calculated = client._calculate_retry_timeout(remaining_retries, options, headers) + assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] + + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Gitpod) -> None: + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock( + side_effect=httpx.TimeoutException("Test timeout error") + ) + + with pytest.raises(APITimeoutError): + client.identity.with_streaming_response.get_authenticated_identity().__enter__() + + assert _get_open_connections(self.client) == 0 + + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Gitpod) -> None: + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock(return_value=httpx.Response(500)) + + with pytest.raises(APIStatusError): + client.identity.with_streaming_response.get_authenticated_identity().__enter__() + assert _get_open_connections(self.client) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) + def test_retries_taken( + self, + client: Gitpod, + failures_before_success: int, + failure_mode: Literal["status", "exception"], + respx_mock: MockRouter, + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + if failure_mode == "exception": + raise RuntimeError("oops") + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock(side_effect=retry_handler) + + response = client.identity.with_raw_response.get_authenticated_identity() + + assert response.retries_taken == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_omit_retry_count_header( + self, client: Gitpod, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock(side_effect=retry_handler) + + response = client.identity.with_raw_response.get_authenticated_identity( + extra_headers={"x-stainless-retry-count": Omit()} + ) + + assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_overwrite_retry_count_header( + self, client: Gitpod, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock(side_effect=retry_handler) + + response = client.identity.with_raw_response.get_authenticated_identity( + extra_headers={"x-stainless-retry-count": "42"} + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" + + def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects(self, respx_mock: MockRouter) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + self.client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" + + +class TestAsyncGitpod: + client = AsyncGitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_raw_response(self, respx_mock: MockRouter) -> None: + respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await self.client.post("/foo", cast_to=httpx.Response) + assert response.status_code == 200 + assert isinstance(response, httpx.Response) + assert response.json() == {"foo": "bar"} + + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + respx_mock.post("/foo").mock( + return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') + ) + + response = await self.client.post("/foo", cast_to=httpx.Response) + assert response.status_code == 200 + assert isinstance(response, httpx.Response) + assert response.json() == {"foo": "bar"} + + def test_copy(self) -> None: + copied = self.client.copy() + assert id(copied) != id(self.client) + + copied = self.client.copy(bearer_token="another My Bearer Token") + assert copied.bearer_token == "another My Bearer Token" + assert self.client.bearer_token == "My Bearer Token" + + def test_copy_default_options(self) -> None: + # options that have a default are overridden correctly + copied = self.client.copy(max_retries=7) + assert copied.max_retries == 7 + assert self.client.max_retries == 2 + + copied2 = copied.copy(max_retries=6) + assert copied2.max_retries == 6 + assert copied.max_retries == 7 + + # timeout + assert isinstance(self.client.timeout, httpx.Timeout) + copied = self.client.copy(timeout=None) + assert copied.timeout is None + assert isinstance(self.client.timeout, httpx.Timeout) + + def test_copy_default_headers(self) -> None: + client = AsyncGitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + default_headers={"X-Foo": "bar"}, + ) + assert client.default_headers["X-Foo"] == "bar" + + # does not override the already given value when not specified + copied = client.copy() + assert copied.default_headers["X-Foo"] == "bar" + + # merges already given headers + copied = client.copy(default_headers={"X-Bar": "stainless"}) + assert copied.default_headers["X-Foo"] == "bar" + assert copied.default_headers["X-Bar"] == "stainless" + + # uses new values for any already given headers + copied = client.copy(default_headers={"X-Foo": "stainless"}) + assert copied.default_headers["X-Foo"] == "stainless" + + # set_default_headers + + # completely overrides already set values + copied = client.copy(set_default_headers={}) + assert copied.default_headers.get("X-Foo") is None + + copied = client.copy(set_default_headers={"X-Bar": "Robert"}) + assert copied.default_headers["X-Bar"] == "Robert" + + with pytest.raises( + ValueError, + match="`default_headers` and `set_default_headers` arguments are mutually exclusive", + ): + client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + + def test_copy_default_query(self) -> None: + client = AsyncGitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, default_query={"foo": "bar"} + ) + assert _get_params(client)["foo"] == "bar" + + # does not override the already given value when not specified + copied = client.copy() + assert _get_params(copied)["foo"] == "bar" + + # merges already given params + copied = client.copy(default_query={"bar": "stainless"}) + params = _get_params(copied) + assert params["foo"] == "bar" + assert params["bar"] == "stainless" + + # uses new values for any already given headers + copied = client.copy(default_query={"foo": "stainless"}) + assert _get_params(copied)["foo"] == "stainless" + + # set_default_query + + # completely overrides already set values + copied = client.copy(set_default_query={}) + assert _get_params(copied) == {} + + copied = client.copy(set_default_query={"bar": "Robert"}) + assert _get_params(copied)["bar"] == "Robert" + + with pytest.raises( + ValueError, + # TODO: update + match="`default_query` and `set_default_query` arguments are mutually exclusive", + ): + client.copy(set_default_query={}, default_query={"foo": "Bar"}) + + def test_copy_signature(self) -> None: + # ensure the same parameters that can be passed to the client are defined in the `.copy()` method + init_signature = inspect.signature( + # mypy doesn't like that we access the `__init__` property. + self.client.__init__, # type: ignore[misc] + ) + copy_signature = inspect.signature(self.client.copy) + exclude_params = {"transport", "proxies", "_strict_response_validation"} + + for name in init_signature.parameters.keys(): + if name in exclude_params: + continue + + copy_param = copy_signature.parameters.get(name) + assert copy_param is not None, f"copy() signature is missing the {name} param" + + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") + def test_copy_build_request(self) -> None: + options = FinalRequestOptions(method="get", url="/foo") + + def build_request(options: FinalRequestOptions) -> None: + client = self.client.copy() + client._build_request(options) + + # ensure that the machinery is warmed up before tracing starts. + build_request(options) + gc.collect() + + tracemalloc.start(1000) + + snapshot_before = tracemalloc.take_snapshot() + + ITERATIONS = 10 + for _ in range(ITERATIONS): + build_request(options) + + gc.collect() + snapshot_after = tracemalloc.take_snapshot() + + tracemalloc.stop() + + def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.StatisticDiff) -> None: + if diff.count == 0: + # Avoid false positives by considering only leaks (i.e. allocations that persist). + return + + if diff.count % ITERATIONS != 0: + # Avoid false positives by considering only leaks that appear per iteration. + return + + for frame in diff.traceback: + if any( + frame.filename.endswith(fragment) + for fragment in [ + # to_raw_response_wrapper leaks through the @functools.wraps() decorator. + # + # removing the decorator fixes the leak for reasons we don't understand. + "gitpod/_legacy_response.py", + "gitpod/_response.py", + # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason. + "gitpod/_compat.py", + # Standard library leaks we don't care about. + "/logging/__init__.py", + ] + ): + return + + leaks.append(diff) + + leaks: list[tracemalloc.StatisticDiff] = [] + for diff in snapshot_after.compare_to(snapshot_before, "traceback"): + add_leak(leaks, diff) + if leaks: + for leak in leaks: + print("MEMORY LEAK:", leak) + for frame in leak.traceback: + print(frame) + raise AssertionError() + + async def test_request_timeout(self) -> None: + request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT + + request = self.client._build_request( + FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) + ) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(100.0) + + async def test_client_timeout_option(self) -> None: + client = AsyncGitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, timeout=httpx.Timeout(0) + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(0) + + async def test_http_client_timeout_option(self) -> None: + # custom timeout given to the httpx client should be used + async with httpx.AsyncClient(timeout=None) as http_client: + client = AsyncGitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(None) + + # no timeout given to the httpx client should not use the httpx default + async with httpx.AsyncClient() as http_client: + client = AsyncGitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT + + # explicitly passing the default timeout currently results in it being ignored + async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: + client = AsyncGitpod( + base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT # our default + + def test_invalid_http_client(self) -> None: + with pytest.raises(TypeError, match="Invalid `http_client` arg"): + with httpx.Client() as http_client: + AsyncGitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + http_client=cast(Any, http_client), + ) + + def test_default_headers_option(self) -> None: + client = AsyncGitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + default_headers={"X-Foo": "bar"}, + ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "bar" + assert request.headers.get("x-stainless-lang") == "python" + + client2 = AsyncGitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + default_headers={ + "X-Foo": "stainless", + "X-Stainless-Lang": "my-overriding-header", + }, + ) + request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "stainless" + assert request.headers.get("x-stainless-lang") == "my-overriding-header" + + def test_validate_headers(self) -> None: + client = AsyncGitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("Authorization") == f"Bearer {bearer_token}" + + with pytest.raises(GitpodError): + with update_env(**{"GITPOD_API_KEY": Omit()}): + client2 = AsyncGitpod(base_url=base_url, bearer_token=None, _strict_response_validation=True) + _ = client2 + + def test_default_query_option(self) -> None: + client = AsyncGitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + default_query={"query_param": "bar"}, + ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + url = httpx.URL(request.url) + assert dict(url.params) == {"query_param": "bar"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/foo", + params={"foo": "baz", "query_param": "overridden"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} + + def test_request_extra_json(self) -> None: + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + extra_json={"baz": False}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"foo": "bar", "baz": False} + + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + extra_json={"baz": False}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"baz": False} + + # `extra_json` takes priority over `json_data` when keys clash + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar", "baz": True}, + extra_json={"baz": None}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"foo": "bar", "baz": None} + + def test_request_extra_headers(self) -> None: + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options(extra_headers={"X-Foo": "Foo"}), + ), + ) + assert request.headers.get("X-Foo") == "Foo" + + # `extra_headers` takes priority over `default_headers` when keys clash + request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + extra_headers={"X-Bar": "false"}, + ), + ), + ) + assert request.headers.get("X-Bar") == "false" + + def test_request_extra_query(self) -> None: + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + extra_query={"my_query_param": "Foo"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"my_query_param": "Foo"} + + # if both `query` and `extra_query` are given, they are merged + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + query={"bar": "1"}, + extra_query={"foo": "2"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"bar": "1", "foo": "2"} + + # `extra_query` takes priority over `query` when keys clash + request = self.client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + query={"foo": "1"}, + extra_query={"foo": "2"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"foo": "2"} + + def test_multipart_repeating_array(self, async_client: AsyncGitpod) -> None: + request = async_client._build_request( + FinalRequestOptions.construct( + method="post", + url="/foo", + headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, + json_data={"array": ["foo", "bar"]}, + files=[("foo.txt", b"hello world")], + ) + ) + + assert request.read().split(b"\r\n") == [ + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="array[]"', + b"", + b"foo", + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="array[]"', + b"", + b"bar", + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="foo.txt"; filename="upload"', + b"Content-Type: application/octet-stream", + b"", + b"hello world", + b"--6b7ba517decee4a450543ea6ae821c82--", + b"", + ] + + @pytest.mark.respx(base_url=base_url) + async def test_basic_union_response(self, respx_mock: MockRouter) -> None: + class Model1(BaseModel): + name: str + + class Model2(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model2) + assert response.foo == "bar" + + @pytest.mark.respx(base_url=base_url) + async def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + """Union of objects with the same field name using a different type""" + + class Model1(BaseModel): + foo: int + + class Model2(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model2) + assert response.foo == "bar" + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) + + response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model1) + assert response.foo == 1 + + @pytest.mark.respx(base_url=base_url) + async def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + """ + Response that sets Content-Type to something other than application/json but returns json data + """ + + class Model(BaseModel): + foo: int + + respx_mock.get("/foo").mock( + return_value=httpx.Response( + 200, + content=json.dumps({"foo": 2}), + headers={"Content-Type": "application/text"}, + ) + ) + + response = await self.client.get("/foo", cast_to=Model) + assert isinstance(response, Model) + assert response.foo == 2 + + def test_base_url_setter(self) -> None: + client = AsyncGitpod( + base_url="https://example.com/from_init", bearer_token=bearer_token, _strict_response_validation=True + ) + assert client.base_url == "https://example.com/from_init/" + + client.base_url = "https://example.com/from_setter" # type: ignore[assignment] + + assert client.base_url == "https://example.com/from_setter/" + + def test_base_url_env(self) -> None: + with update_env(GITPOD_BASE_URL="http://localhost:5000/from/env"): + client = AsyncGitpod(bearer_token=bearer_token, _strict_response_validation=True) + assert client.base_url == "http://localhost:5000/from/env/" + + @pytest.mark.parametrize( + "client", + [ + AsyncGitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + ), + AsyncGitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + http_client=httpx.AsyncClient(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_base_url_trailing_slash(self, client: AsyncGitpod) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "http://localhost:5000/custom/path/foo" + + @pytest.mark.parametrize( + "client", + [ + AsyncGitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + ), + AsyncGitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + http_client=httpx.AsyncClient(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_base_url_no_trailing_slash(self, client: AsyncGitpod) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "http://localhost:5000/custom/path/foo" + + @pytest.mark.parametrize( + "client", + [ + AsyncGitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + ), + AsyncGitpod( + base_url="http://localhost:5000/custom/path/", + bearer_token=bearer_token, + _strict_response_validation=True, + http_client=httpx.AsyncClient(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_absolute_request_url(self, client: AsyncGitpod) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="https://myapi.com/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "https://myapi.com/foo" + + async def test_copied_client_does_not_close_http(self) -> None: + client = AsyncGitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + assert not client.is_closed() + + copied = client.copy() + assert copied is not client + + del copied + + await asyncio.sleep(0.2) + assert not client.is_closed() + + async def test_client_context_manager(self) -> None: + client = AsyncGitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + async with client as c2: + assert c2 is client + assert not c2.is_closed() + assert not client.is_closed() + assert client.is_closed() + + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + class Model(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) + + with pytest.raises(APIResponseValidationError) as exc: + await self.client.get("/foo", cast_to=Model) + + assert isinstance(exc.value.__cause__, ValidationError) + + async def test_client_max_retries_validation(self) -> None: + with pytest.raises(TypeError, match=r"max_retries cannot be None"): + AsyncGitpod( + base_url=base_url, + bearer_token=bearer_token, + _strict_response_validation=True, + max_retries=cast(Any, None), + ) + + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: + class Model(BaseModel): + name: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format")) + + strict_client = AsyncGitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + + with pytest.raises(APIResponseValidationError): + await strict_client.get("/foo", cast_to=Model) + + client = AsyncGitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=False) + + response = await client.get("/foo", cast_to=Model) + assert isinstance(response, str) # type: ignore[unreachable] + + @pytest.mark.parametrize( + "remaining_retries,retry_after,timeout", + [ + [3, "20", 20], + [3, "0", 0.5], + [3, "-10", 0.5], + [3, "60", 60], + [3, "61", 0.5], + [3, "Fri, 29 Sep 2023 16:26:57 GMT", 20], + [3, "Fri, 29 Sep 2023 16:26:37 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:27:37 GMT", 60], + [3, "Fri, 29 Sep 2023 16:27:38 GMT", 0.5], + [3, "99999999999999999999999999999999999", 0.5], + [3, "Zun, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "", 0.5], + [2, "", 0.5 * 2.0], + [1, "", 0.5 * 4.0], + [-1100, "", 8], # test large number potentially overflowing + ], + ) + @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) + @pytest.mark.asyncio + async def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: + client = AsyncGitpod(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) + + headers = httpx.Headers({"retry-after": retry_after}) + options = FinalRequestOptions(method="get", url="/foo", max_retries=3) + calculated = client._calculate_retry_timeout(remaining_retries, options, headers) + assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] + + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncGitpod) -> None: + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock( + side_effect=httpx.TimeoutException("Test timeout error") + ) + + with pytest.raises(APITimeoutError): + await async_client.identity.with_streaming_response.get_authenticated_identity().__aenter__() + + assert _get_open_connections(self.client) == 0 + + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncGitpod) -> None: + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock(return_value=httpx.Response(500)) + + with pytest.raises(APIStatusError): + await async_client.identity.with_streaming_response.get_authenticated_identity().__aenter__() + assert _get_open_connections(self.client) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) + async def test_retries_taken( + self, + async_client: AsyncGitpod, + failures_before_success: int, + failure_mode: Literal["status", "exception"], + respx_mock: MockRouter, + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + if failure_mode == "exception": + raise RuntimeError("oops") + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock(side_effect=retry_handler) + + response = await client.identity.with_raw_response.get_authenticated_identity() + + assert response.retries_taken == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_omit_retry_count_header( + self, async_client: AsyncGitpod, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock(side_effect=retry_handler) + + response = await client.identity.with_raw_response.get_authenticated_identity( + extra_headers={"x-stainless-retry-count": Omit()} + ) + + assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gitpod._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_overwrite_retry_count_header( + self, async_client: AsyncGitpod, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/gitpod.v1.IdentityService/GetAuthenticatedIdentity").mock(side_effect=retry_handler) + + response = await client.identity.with_raw_response.get_authenticated_identity( + extra_headers={"x-stainless-retry-count": "42"} + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" + + def test_get_platform(self) -> None: + # A previous implementation of asyncify could leave threads unterminated when + # used with nest_asyncio. + # + # Since nest_asyncio.apply() is global and cannot be un-applied, this + # test is run in a separate process to avoid affecting other tests. + test_code = dedent(""" + import asyncio + import nest_asyncio + import threading + + from gitpod._utils import asyncify + from gitpod._base_client import get_platform + + async def test_main() -> None: + result = await asyncify(get_platform)() + print(result) + for thread in threading.enumerate(): + print(thread.name) + + nest_asyncio.apply() + asyncio.run(test_main()) + """) + with subprocess.Popen( + [sys.executable, "-c", test_code], + text=True, + ) as process: + timeout = 10 # seconds + + start_time = time.monotonic() + while True: + return_code = process.poll() + if return_code is not None: + if return_code != 0: + raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") + + # success + break + + if time.monotonic() - start_time > timeout: + process.kill() + raise AssertionError("calling get_platform using asyncify resulted in a hung process") + + time.sleep(0.1) + + async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultAsyncHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + async def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultAsyncHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects(self, respx_mock: MockRouter) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + await self.client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py new file mode 100644 index 0000000..c498f53 --- /dev/null +++ b/tests/test_deepcopy.py @@ -0,0 +1,58 @@ +from gitpod._utils import deepcopy_minimal + + +def assert_different_identities(obj1: object, obj2: object) -> None: + assert obj1 == obj2 + assert id(obj1) != id(obj2) + + +def test_simple_dict() -> None: + obj1 = {"foo": "bar"} + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + + +def test_nested_dict() -> None: + obj1 = {"foo": {"bar": True}} + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert_different_identities(obj1["foo"], obj2["foo"]) + + +def test_complex_nested_dict() -> None: + obj1 = {"foo": {"bar": [{"hello": "world"}]}} + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert_different_identities(obj1["foo"], obj2["foo"]) + assert_different_identities(obj1["foo"]["bar"], obj2["foo"]["bar"]) + assert_different_identities(obj1["foo"]["bar"][0], obj2["foo"]["bar"][0]) + + +def test_simple_list() -> None: + obj1 = ["a", "b", "c"] + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + + +def test_nested_list() -> None: + obj1 = ["a", [1, 2, 3]] + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert_different_identities(obj1[1], obj2[1]) + + +class MyObject: ... + + +def test_ignores_other_types() -> None: + # custom classes + my_obj = MyObject() + obj1 = {"foo": my_obj} + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert obj1["foo"] is my_obj + + # tuples + obj3 = ("a", "b") + obj4 = deepcopy_minimal(obj3) + assert obj3 is obj4 diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py new file mode 100644 index 0000000..0ca5a8d --- /dev/null +++ b/tests/test_extract_files.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from typing import Sequence + +import pytest + +from gitpod._types import FileTypes +from gitpod._utils import extract_files + + +def test_removes_files_from_input() -> None: + query = {"foo": "bar"} + assert extract_files(query, paths=[]) == [] + assert query == {"foo": "bar"} + + query2 = {"foo": b"Bar", "hello": "world"} + assert extract_files(query2, paths=[["foo"]]) == [("foo", b"Bar")] + assert query2 == {"hello": "world"} + + query3 = {"foo": {"foo": {"bar": b"Bar"}}, "hello": "world"} + assert extract_files(query3, paths=[["foo", "foo", "bar"]]) == [("foo[foo][bar]", b"Bar")] + assert query3 == {"foo": {"foo": {}}, "hello": "world"} + + query4 = {"foo": {"bar": b"Bar", "baz": "foo"}, "hello": "world"} + assert extract_files(query4, paths=[["foo", "bar"]]) == [("foo[bar]", b"Bar")] + assert query4 == {"hello": "world", "foo": {"baz": "foo"}} + + +def test_multiple_files() -> None: + query = {"documents": [{"file": b"My first file"}, {"file": b"My second file"}]} + assert extract_files(query, paths=[["documents", "<array>", "file"]]) == [ + ("documents[][file]", b"My first file"), + ("documents[][file]", b"My second file"), + ] + assert query == {"documents": [{}, {}]} + + +@pytest.mark.parametrize( + "query,paths,expected", + [ + [ + {"foo": {"bar": "baz"}}, + [["foo", "<array>", "bar"]], + [], + ], + [ + {"foo": ["bar", "baz"]}, + [["foo", "bar"]], + [], + ], + [ + {"foo": {"bar": "baz"}}, + [["foo", "foo"]], + [], + ], + ], + ids=["dict expecting array", "array expecting dict", "unknown keys"], +) +def test_ignores_incorrect_paths( + query: dict[str, object], + paths: Sequence[Sequence[str]], + expected: list[tuple[str, FileTypes]], +) -> None: + assert extract_files(query, paths=paths) == expected diff --git a/tests/test_files.py b/tests/test_files.py new file mode 100644 index 0000000..efde0d4 --- /dev/null +++ b/tests/test_files.py @@ -0,0 +1,51 @@ +from pathlib import Path + +import anyio +import pytest +from dirty_equals import IsDict, IsList, IsBytes, IsTuple + +from gitpod._files import to_httpx_files, async_to_httpx_files + +readme_path = Path(__file__).parent.parent.joinpath("README.md") + + +def test_pathlib_includes_file_name() -> None: + result = to_httpx_files({"file": readme_path}) + print(result) + assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) + + +def test_tuple_input() -> None: + result = to_httpx_files([("file", readme_path)]) + print(result) + assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) + + +@pytest.mark.asyncio +async def test_async_pathlib_includes_file_name() -> None: + result = await async_to_httpx_files({"file": readme_path}) + print(result) + assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) + + +@pytest.mark.asyncio +async def test_async_supports_anyio_path() -> None: + result = await async_to_httpx_files({"file": anyio.Path(readme_path)}) + print(result) + assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) + + +@pytest.mark.asyncio +async def test_async_tuple_input() -> None: + result = await async_to_httpx_files([("file", readme_path)]) + print(result) + assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) + + +def test_string_not_allowed() -> None: + with pytest.raises(TypeError, match="Expected file types input to be a FileContent type or to be a tuple"): + to_httpx_files( + { + "file": "foo", # type: ignore + } + ) diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..26429e1 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,936 @@ +import json +from typing import Any, Dict, List, Union, Optional, cast +from datetime import datetime, timezone +from typing_extensions import Literal, Annotated, TypeAliasType + +import pytest +import pydantic +from pydantic import Field + +from gitpod._utils import PropertyInfo +from gitpod._compat import PYDANTIC_V2, parse_obj, model_dump, model_json +from gitpod._models import BaseModel, construct_type + + +class BasicModel(BaseModel): + foo: str + + +@pytest.mark.parametrize("value", ["hello", 1], ids=["correct type", "mismatched"]) +def test_basic(value: object) -> None: + m = BasicModel.construct(foo=value) + assert m.foo == value + + +def test_directly_nested_model() -> None: + class NestedModel(BaseModel): + nested: BasicModel + + m = NestedModel.construct(nested={"foo": "Foo!"}) + assert m.nested.foo == "Foo!" + + # mismatched types + m = NestedModel.construct(nested="hello!") + assert cast(Any, m.nested) == "hello!" + + +def test_optional_nested_model() -> None: + class NestedModel(BaseModel): + nested: Optional[BasicModel] + + m1 = NestedModel.construct(nested=None) + assert m1.nested is None + + m2 = NestedModel.construct(nested={"foo": "bar"}) + assert m2.nested is not None + assert m2.nested.foo == "bar" + + # mismatched types + m3 = NestedModel.construct(nested={"foo"}) + assert isinstance(cast(Any, m3.nested), set) + assert cast(Any, m3.nested) == {"foo"} + + +def test_list_nested_model() -> None: + class NestedModel(BaseModel): + nested: List[BasicModel] + + m = NestedModel.construct(nested=[{"foo": "bar"}, {"foo": "2"}]) + assert m.nested is not None + assert isinstance(m.nested, list) + assert len(m.nested) == 2 + assert m.nested[0].foo == "bar" + assert m.nested[1].foo == "2" + + # mismatched types + m = NestedModel.construct(nested=True) + assert cast(Any, m.nested) is True + + m = NestedModel.construct(nested=[False]) + assert cast(Any, m.nested) == [False] + + +def test_optional_list_nested_model() -> None: + class NestedModel(BaseModel): + nested: Optional[List[BasicModel]] + + m1 = NestedModel.construct(nested=[{"foo": "bar"}, {"foo": "2"}]) + assert m1.nested is not None + assert isinstance(m1.nested, list) + assert len(m1.nested) == 2 + assert m1.nested[0].foo == "bar" + assert m1.nested[1].foo == "2" + + m2 = NestedModel.construct(nested=None) + assert m2.nested is None + + # mismatched types + m3 = NestedModel.construct(nested={1}) + assert cast(Any, m3.nested) == {1} + + m4 = NestedModel.construct(nested=[False]) + assert cast(Any, m4.nested) == [False] + + +def test_list_optional_items_nested_model() -> None: + class NestedModel(BaseModel): + nested: List[Optional[BasicModel]] + + m = NestedModel.construct(nested=[None, {"foo": "bar"}]) + assert m.nested is not None + assert isinstance(m.nested, list) + assert len(m.nested) == 2 + assert m.nested[0] is None + assert m.nested[1] is not None + assert m.nested[1].foo == "bar" + + # mismatched types + m3 = NestedModel.construct(nested="foo") + assert cast(Any, m3.nested) == "foo" + + m4 = NestedModel.construct(nested=[False]) + assert cast(Any, m4.nested) == [False] + + +def test_list_mismatched_type() -> None: + class NestedModel(BaseModel): + nested: List[str] + + m = NestedModel.construct(nested=False) + assert cast(Any, m.nested) is False + + +def test_raw_dictionary() -> None: + class NestedModel(BaseModel): + nested: Dict[str, str] + + m = NestedModel.construct(nested={"hello": "world"}) + assert m.nested == {"hello": "world"} + + # mismatched types + m = NestedModel.construct(nested=False) + assert cast(Any, m.nested) is False + + +def test_nested_dictionary_model() -> None: + class NestedModel(BaseModel): + nested: Dict[str, BasicModel] + + m = NestedModel.construct(nested={"hello": {"foo": "bar"}}) + assert isinstance(m.nested, dict) + assert m.nested["hello"].foo == "bar" + + # mismatched types + m = NestedModel.construct(nested={"hello": False}) + assert cast(Any, m.nested["hello"]) is False + + +def test_unknown_fields() -> None: + m1 = BasicModel.construct(foo="foo", unknown=1) + assert m1.foo == "foo" + assert cast(Any, m1).unknown == 1 + + m2 = BasicModel.construct(foo="foo", unknown={"foo_bar": True}) + assert m2.foo == "foo" + assert cast(Any, m2).unknown == {"foo_bar": True} + + assert model_dump(m2) == {"foo": "foo", "unknown": {"foo_bar": True}} + + +def test_strict_validation_unknown_fields() -> None: + class Model(BaseModel): + foo: str + + model = parse_obj(Model, dict(foo="hello!", user="Robert")) + assert model.foo == "hello!" + assert cast(Any, model).user == "Robert" + + assert model_dump(model) == {"foo": "hello!", "user": "Robert"} + + +def test_aliases() -> None: + class Model(BaseModel): + my_field: int = Field(alias="myField") + + m = Model.construct(myField=1) + assert m.my_field == 1 + + # mismatched types + m = Model.construct(myField={"hello": False}) + assert cast(Any, m.my_field) == {"hello": False} + + +def test_repr() -> None: + model = BasicModel(foo="bar") + assert str(model) == "BasicModel(foo='bar')" + assert repr(model) == "BasicModel(foo='bar')" + + +def test_repr_nested_model() -> None: + class Child(BaseModel): + name: str + age: int + + class Parent(BaseModel): + name: str + child: Child + + model = Parent(name="Robert", child=Child(name="Foo", age=5)) + assert str(model) == "Parent(name='Robert', child=Child(name='Foo', age=5))" + assert repr(model) == "Parent(name='Robert', child=Child(name='Foo', age=5))" + + +def test_optional_list() -> None: + class Submodel(BaseModel): + name: str + + class Model(BaseModel): + items: Optional[List[Submodel]] + + m = Model.construct(items=None) + assert m.items is None + + m = Model.construct(items=[]) + assert m.items == [] + + m = Model.construct(items=[{"name": "Robert"}]) + assert m.items is not None + assert len(m.items) == 1 + assert m.items[0].name == "Robert" + + +def test_nested_union_of_models() -> None: + class Submodel1(BaseModel): + bar: bool + + class Submodel2(BaseModel): + thing: str + + class Model(BaseModel): + foo: Union[Submodel1, Submodel2] + + m = Model.construct(foo={"thing": "hello"}) + assert isinstance(m.foo, Submodel2) + assert m.foo.thing == "hello" + + +def test_nested_union_of_mixed_types() -> None: + class Submodel1(BaseModel): + bar: bool + + class Model(BaseModel): + foo: Union[Submodel1, Literal[True], Literal["CARD_HOLDER"]] + + m = Model.construct(foo=True) + assert m.foo is True + + m = Model.construct(foo="CARD_HOLDER") + assert m.foo == "CARD_HOLDER" + + m = Model.construct(foo={"bar": False}) + assert isinstance(m.foo, Submodel1) + assert m.foo.bar is False + + +def test_nested_union_multiple_variants() -> None: + class Submodel1(BaseModel): + bar: bool + + class Submodel2(BaseModel): + thing: str + + class Submodel3(BaseModel): + foo: int + + class Model(BaseModel): + foo: Union[Submodel1, Submodel2, None, Submodel3] + + m = Model.construct(foo={"thing": "hello"}) + assert isinstance(m.foo, Submodel2) + assert m.foo.thing == "hello" + + m = Model.construct(foo=None) + assert m.foo is None + + m = Model.construct() + assert m.foo is None + + m = Model.construct(foo={"foo": "1"}) + assert isinstance(m.foo, Submodel3) + assert m.foo.foo == 1 + + +def test_nested_union_invalid_data() -> None: + class Submodel1(BaseModel): + level: int + + class Submodel2(BaseModel): + name: str + + class Model(BaseModel): + foo: Union[Submodel1, Submodel2] + + m = Model.construct(foo=True) + assert cast(bool, m.foo) is True + + m = Model.construct(foo={"name": 3}) + if PYDANTIC_V2: + assert isinstance(m.foo, Submodel1) + assert m.foo.name == 3 # type: ignore + else: + assert isinstance(m.foo, Submodel2) + assert m.foo.name == "3" + + +def test_list_of_unions() -> None: + class Submodel1(BaseModel): + level: int + + class Submodel2(BaseModel): + name: str + + class Model(BaseModel): + items: List[Union[Submodel1, Submodel2]] + + m = Model.construct(items=[{"level": 1}, {"name": "Robert"}]) + assert len(m.items) == 2 + assert isinstance(m.items[0], Submodel1) + assert m.items[0].level == 1 + assert isinstance(m.items[1], Submodel2) + assert m.items[1].name == "Robert" + + m = Model.construct(items=[{"level": -1}, 156]) + assert len(m.items) == 2 + assert isinstance(m.items[0], Submodel1) + assert m.items[0].level == -1 + assert cast(Any, m.items[1]) == 156 + + +def test_union_of_lists() -> None: + class SubModel1(BaseModel): + level: int + + class SubModel2(BaseModel): + name: str + + class Model(BaseModel): + items: Union[List[SubModel1], List[SubModel2]] + + # with one valid entry + m = Model.construct(items=[{"name": "Robert"}]) + assert len(m.items) == 1 + assert isinstance(m.items[0], SubModel2) + assert m.items[0].name == "Robert" + + # with two entries pointing to different types + m = Model.construct(items=[{"level": 1}, {"name": "Robert"}]) + assert len(m.items) == 2 + assert isinstance(m.items[0], SubModel1) + assert m.items[0].level == 1 + assert isinstance(m.items[1], SubModel1) + assert cast(Any, m.items[1]).name == "Robert" + + # with two entries pointing to *completely* different types + m = Model.construct(items=[{"level": -1}, 156]) + assert len(m.items) == 2 + assert isinstance(m.items[0], SubModel1) + assert m.items[0].level == -1 + assert cast(Any, m.items[1]) == 156 + + +def test_dict_of_union() -> None: + class SubModel1(BaseModel): + name: str + + class SubModel2(BaseModel): + foo: str + + class Model(BaseModel): + data: Dict[str, Union[SubModel1, SubModel2]] + + m = Model.construct(data={"hello": {"name": "there"}, "foo": {"foo": "bar"}}) + assert len(list(m.data.keys())) == 2 + assert isinstance(m.data["hello"], SubModel1) + assert m.data["hello"].name == "there" + assert isinstance(m.data["foo"], SubModel2) + assert m.data["foo"].foo == "bar" + + # TODO: test mismatched type + + +def test_double_nested_union() -> None: + class SubModel1(BaseModel): + name: str + + class SubModel2(BaseModel): + bar: str + + class Model(BaseModel): + data: Dict[str, List[Union[SubModel1, SubModel2]]] + + m = Model.construct(data={"foo": [{"bar": "baz"}, {"name": "Robert"}]}) + assert len(m.data["foo"]) == 2 + + entry1 = m.data["foo"][0] + assert isinstance(entry1, SubModel2) + assert entry1.bar == "baz" + + entry2 = m.data["foo"][1] + assert isinstance(entry2, SubModel1) + assert entry2.name == "Robert" + + # TODO: test mismatched type + + +def test_union_of_dict() -> None: + class SubModel1(BaseModel): + name: str + + class SubModel2(BaseModel): + foo: str + + class Model(BaseModel): + data: Union[Dict[str, SubModel1], Dict[str, SubModel2]] + + m = Model.construct(data={"hello": {"name": "there"}, "foo": {"foo": "bar"}}) + assert len(list(m.data.keys())) == 2 + assert isinstance(m.data["hello"], SubModel1) + assert m.data["hello"].name == "there" + assert isinstance(m.data["foo"], SubModel1) + assert cast(Any, m.data["foo"]).foo == "bar" + + +def test_iso8601_datetime() -> None: + class Model(BaseModel): + created_at: datetime + + expected = datetime(2019, 12, 27, 18, 11, 19, 117000, tzinfo=timezone.utc) + + if PYDANTIC_V2: + expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' + else: + expected_json = '{"created_at": "2019-12-27T18:11:19.117000+00:00"}' + + model = Model.construct(created_at="2019-12-27T18:11:19.117Z") + assert model.created_at == expected + assert model_json(model) == expected_json + + model = parse_obj(Model, dict(created_at="2019-12-27T18:11:19.117Z")) + assert model.created_at == expected + assert model_json(model) == expected_json + + +def test_does_not_coerce_int() -> None: + class Model(BaseModel): + bar: int + + assert Model.construct(bar=1).bar == 1 + assert Model.construct(bar=10.9).bar == 10.9 + assert Model.construct(bar="19").bar == "19" # type: ignore[comparison-overlap] + assert Model.construct(bar=False).bar is False + + +def test_int_to_float_safe_conversion() -> None: + class Model(BaseModel): + float_field: float + + m = Model.construct(float_field=10) + assert m.float_field == 10.0 + assert isinstance(m.float_field, float) + + m = Model.construct(float_field=10.12) + assert m.float_field == 10.12 + assert isinstance(m.float_field, float) + + # number too big + m = Model.construct(float_field=2**53 + 1) + assert m.float_field == 2**53 + 1 + assert isinstance(m.float_field, int) + + +def test_deprecated_alias() -> None: + class Model(BaseModel): + resource_id: str = Field(alias="model_id") + + @property + def model_id(self) -> str: + return self.resource_id + + m = Model.construct(model_id="id") + assert m.model_id == "id" + assert m.resource_id == "id" + assert m.resource_id is m.model_id + + m = parse_obj(Model, {"model_id": "id"}) + assert m.model_id == "id" + assert m.resource_id == "id" + assert m.resource_id is m.model_id + + +def test_omitted_fields() -> None: + class Model(BaseModel): + resource_id: Optional[str] = None + + m = Model.construct() + assert m.resource_id is None + assert "resource_id" not in m.model_fields_set + + m = Model.construct(resource_id=None) + assert m.resource_id is None + assert "resource_id" in m.model_fields_set + + m = Model.construct(resource_id="foo") + assert m.resource_id == "foo" + assert "resource_id" in m.model_fields_set + + +def test_to_dict() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert m.to_dict() == {"FOO": "hello"} + assert m.to_dict(use_api_names=False) == {"foo": "hello"} + + m2 = Model() + assert m2.to_dict() == {} + assert m2.to_dict(exclude_unset=False) == {"FOO": None} + assert m2.to_dict(exclude_unset=False, exclude_none=True) == {} + assert m2.to_dict(exclude_unset=False, exclude_defaults=True) == {} + + m3 = Model(FOO=None) + assert m3.to_dict() == {"FOO": None} + assert m3.to_dict(exclude_none=True) == {} + assert m3.to_dict(exclude_defaults=True) == {} + + class Model2(BaseModel): + created_at: datetime + + time_str = "2024-03-21T11:39:01.275859" + m4 = Model2.construct(created_at=time_str) + assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} + assert m4.to_dict(mode="json") == {"created_at": time_str} + + if not PYDANTIC_V2: + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.to_dict(warnings=False) + + +def test_forwards_compat_model_dump_method() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert m.model_dump() == {"foo": "hello"} + assert m.model_dump(include={"bar"}) == {} + assert m.model_dump(exclude={"foo"}) == {} + assert m.model_dump(by_alias=True) == {"FOO": "hello"} + + m2 = Model() + assert m2.model_dump() == {"foo": None} + assert m2.model_dump(exclude_unset=True) == {} + assert m2.model_dump(exclude_none=True) == {} + assert m2.model_dump(exclude_defaults=True) == {} + + m3 = Model(FOO=None) + assert m3.model_dump() == {"foo": None} + assert m3.model_dump(exclude_none=True) == {} + + if not PYDANTIC_V2: + with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): + m.model_dump(round_trip=True) + + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.model_dump(warnings=False) + + +def test_compat_method_no_error_for_warnings() -> None: + class Model(BaseModel): + foo: Optional[str] + + m = Model(foo="hello") + assert isinstance(model_dump(m, warnings=False), dict) + + +def test_to_json() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert json.loads(m.to_json()) == {"FOO": "hello"} + assert json.loads(m.to_json(use_api_names=False)) == {"foo": "hello"} + + if PYDANTIC_V2: + assert m.to_json(indent=None) == '{"FOO":"hello"}' + else: + assert m.to_json(indent=None) == '{"FOO": "hello"}' + + m2 = Model() + assert json.loads(m2.to_json()) == {} + assert json.loads(m2.to_json(exclude_unset=False)) == {"FOO": None} + assert json.loads(m2.to_json(exclude_unset=False, exclude_none=True)) == {} + assert json.loads(m2.to_json(exclude_unset=False, exclude_defaults=True)) == {} + + m3 = Model(FOO=None) + assert json.loads(m3.to_json()) == {"FOO": None} + assert json.loads(m3.to_json(exclude_none=True)) == {} + + if not PYDANTIC_V2: + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.to_json(warnings=False) + + +def test_forwards_compat_model_dump_json_method() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert json.loads(m.model_dump_json()) == {"foo": "hello"} + assert json.loads(m.model_dump_json(include={"bar"})) == {} + assert json.loads(m.model_dump_json(include={"foo"})) == {"foo": "hello"} + assert json.loads(m.model_dump_json(by_alias=True)) == {"FOO": "hello"} + + assert m.model_dump_json(indent=2) == '{\n "foo": "hello"\n}' + + m2 = Model() + assert json.loads(m2.model_dump_json()) == {"foo": None} + assert json.loads(m2.model_dump_json(exclude_unset=True)) == {} + assert json.loads(m2.model_dump_json(exclude_none=True)) == {} + assert json.loads(m2.model_dump_json(exclude_defaults=True)) == {} + + m3 = Model(FOO=None) + assert json.loads(m3.model_dump_json()) == {"foo": None} + assert json.loads(m3.model_dump_json(exclude_none=True)) == {} + + if not PYDANTIC_V2: + with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): + m.model_dump_json(round_trip=True) + + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.model_dump_json(warnings=False) + + +def test_type_compat() -> None: + # our model type can be assigned to Pydantic's model type + + def takes_pydantic(model: pydantic.BaseModel) -> None: # noqa: ARG001 + ... + + class OurModel(BaseModel): + foo: Optional[str] = None + + takes_pydantic(OurModel()) + + +def test_annotated_types() -> None: + class Model(BaseModel): + value: str + + m = construct_type( + value={"value": "foo"}, + type_=cast(Any, Annotated[Model, "random metadata"]), + ) + assert isinstance(m, Model) + assert m.value == "foo" + + +def test_discriminated_unions_invalid_data() -> None: + class A(BaseModel): + type: Literal["a"] + + data: str + + class B(BaseModel): + type: Literal["b"] + + data: int + + m = construct_type( + value={"type": "b", "data": "foo"}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, B) + assert m.type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + m = construct_type( + value={"type": "a", "data": 100}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, A) + assert m.type == "a" + if PYDANTIC_V2: + assert m.data == 100 # type: ignore[comparison-overlap] + else: + # pydantic v1 automatically converts inputs to strings + # if the expected type is a str + assert m.data == "100" + + +def test_discriminated_unions_unknown_variant() -> None: + class A(BaseModel): + type: Literal["a"] + + data: str + + class B(BaseModel): + type: Literal["b"] + + data: int + + m = construct_type( + value={"type": "c", "data": None, "new_thing": "bar"}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), + ) + + # just chooses the first variant + assert isinstance(m, A) + assert m.type == "c" # type: ignore[comparison-overlap] + assert m.data == None # type: ignore[unreachable] + assert m.new_thing == "bar" + + +def test_discriminated_unions_invalid_data_nested_unions() -> None: + class A(BaseModel): + type: Literal["a"] + + data: str + + class B(BaseModel): + type: Literal["b"] + + data: int + + class C(BaseModel): + type: Literal["c"] + + data: bool + + m = construct_type( + value={"type": "b", "data": "foo"}, + type_=cast(Any, Annotated[Union[Union[A, B], C], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, B) + assert m.type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + m = construct_type( + value={"type": "c", "data": "foo"}, + type_=cast(Any, Annotated[Union[Union[A, B], C], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, C) + assert m.type == "c" + assert m.data == "foo" # type: ignore[comparison-overlap] + + +def test_discriminated_unions_with_aliases_invalid_data() -> None: + class A(BaseModel): + foo_type: Literal["a"] = Field(alias="type") + + data: str + + class B(BaseModel): + foo_type: Literal["b"] = Field(alias="type") + + data: int + + m = construct_type( + value={"type": "b", "data": "foo"}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="foo_type")]), + ) + assert isinstance(m, B) + assert m.foo_type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + m = construct_type( + value={"type": "a", "data": 100}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="foo_type")]), + ) + assert isinstance(m, A) + assert m.foo_type == "a" + if PYDANTIC_V2: + assert m.data == 100 # type: ignore[comparison-overlap] + else: + # pydantic v1 automatically converts inputs to strings + # if the expected type is a str + assert m.data == "100" + + +def test_discriminated_unions_overlapping_discriminators_invalid_data() -> None: + class A(BaseModel): + type: Literal["a"] + + data: bool + + class B(BaseModel): + type: Literal["a"] + + data: int + + m = construct_type( + value={"type": "a", "data": "foo"}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, B) + assert m.type == "a" + assert m.data == "foo" # type: ignore[comparison-overlap] + + +def test_discriminated_unions_invalid_data_uses_cache() -> None: + class A(BaseModel): + type: Literal["a"] + + data: str + + class B(BaseModel): + type: Literal["b"] + + data: int + + UnionType = cast(Any, Union[A, B]) + + assert not hasattr(UnionType, "__discriminator__") + + m = construct_type( + value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) + ) + assert isinstance(m, B) + assert m.type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + discriminator = UnionType.__discriminator__ + assert discriminator is not None + + m = construct_type( + value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) + ) + assert isinstance(m, B) + assert m.type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + # if the discriminator details object stays the same between invocations then + # we hit the cache + assert UnionType.__discriminator__ is discriminator + + +@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +def test_type_alias_type() -> None: + Alias = TypeAliasType("Alias", str) # pyright: ignore + + class Model(BaseModel): + alias: Alias + union: Union[int, Alias] + + m = construct_type(value={"alias": "foo", "union": "bar"}, type_=Model) + assert isinstance(m, Model) + assert isinstance(m.alias, str) + assert m.alias == "foo" + assert isinstance(m.union, str) + assert m.union == "bar" + + +@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +def test_field_named_cls() -> None: + class Model(BaseModel): + cls: str + + m = construct_type(value={"cls": "foo"}, type_=Model) + assert isinstance(m, Model) + assert isinstance(m.cls, str) + + +def test_discriminated_union_case() -> None: + class A(BaseModel): + type: Literal["a"] + + data: bool + + class B(BaseModel): + type: Literal["b"] + + data: List[Union[A, object]] + + class ModelA(BaseModel): + type: Literal["modelA"] + + data: int + + class ModelB(BaseModel): + type: Literal["modelB"] + + required: str + + data: Union[A, B] + + # when constructing ModelA | ModelB, value data doesn't match ModelB exactly - missing `required` + m = construct_type( + value={"type": "modelB", "data": {"type": "a", "data": True}}, + type_=cast(Any, Annotated[Union[ModelA, ModelB], PropertyInfo(discriminator="type")]), + ) + + assert isinstance(m, ModelB) + + +def test_nested_discriminated_union() -> None: + class InnerType1(BaseModel): + type: Literal["type_1"] + + class InnerModel(BaseModel): + inner_value: str + + class InnerType2(BaseModel): + type: Literal["type_2"] + some_inner_model: InnerModel + + class Type1(BaseModel): + base_type: Literal["base_type_1"] + value: Annotated[ + Union[ + InnerType1, + InnerType2, + ], + PropertyInfo(discriminator="type"), + ] + + class Type2(BaseModel): + base_type: Literal["base_type_2"] + + T = Annotated[ + Union[ + Type1, + Type2, + ], + PropertyInfo(discriminator="base_type"), + ] + + model = construct_type( + type_=T, + value={ + "base_type": "base_type_1", + "value": { + "type": "type_2", + }, + }, + ) + assert isinstance(model, Type1) + assert isinstance(model.value, InnerType2) diff --git a/tests/test_qs.py b/tests/test_qs.py new file mode 100644 index 0000000..0ca7188 --- /dev/null +++ b/tests/test_qs.py @@ -0,0 +1,78 @@ +from typing import Any, cast +from functools import partial +from urllib.parse import unquote + +import pytest + +from gitpod._qs import Querystring, stringify + + +def test_empty() -> None: + assert stringify({}) == "" + assert stringify({"a": {}}) == "" + assert stringify({"a": {"b": {"c": {}}}}) == "" + + +def test_basic() -> None: + assert stringify({"a": 1}) == "a=1" + assert stringify({"a": "b"}) == "a=b" + assert stringify({"a": True}) == "a=true" + assert stringify({"a": False}) == "a=false" + assert stringify({"a": 1.23456}) == "a=1.23456" + assert stringify({"a": None}) == "" + + +@pytest.mark.parametrize("method", ["class", "function"]) +def test_nested_dotted(method: str) -> None: + if method == "class": + serialise = Querystring(nested_format="dots").stringify + else: + serialise = partial(stringify, nested_format="dots") + + assert unquote(serialise({"a": {"b": "c"}})) == "a.b=c" + assert unquote(serialise({"a": {"b": "c", "d": "e", "f": "g"}})) == "a.b=c&a.d=e&a.f=g" + assert unquote(serialise({"a": {"b": {"c": {"d": "e"}}}})) == "a.b.c.d=e" + assert unquote(serialise({"a": {"b": True}})) == "a.b=true" + + +def test_nested_brackets() -> None: + assert unquote(stringify({"a": {"b": "c"}})) == "a[b]=c" + assert unquote(stringify({"a": {"b": "c", "d": "e", "f": "g"}})) == "a[b]=c&a[d]=e&a[f]=g" + assert unquote(stringify({"a": {"b": {"c": {"d": "e"}}}})) == "a[b][c][d]=e" + assert unquote(stringify({"a": {"b": True}})) == "a[b]=true" + + +@pytest.mark.parametrize("method", ["class", "function"]) +def test_array_comma(method: str) -> None: + if method == "class": + serialise = Querystring(array_format="comma").stringify + else: + serialise = partial(stringify, array_format="comma") + + assert unquote(serialise({"in": ["foo", "bar"]})) == "in=foo,bar" + assert unquote(serialise({"a": {"b": [True, False]}})) == "a[b]=true,false" + assert unquote(serialise({"a": {"b": [True, False, None, True]}})) == "a[b]=true,false,true" + + +def test_array_repeat() -> None: + assert unquote(stringify({"in": ["foo", "bar"]})) == "in=foo&in=bar" + assert unquote(stringify({"a": {"b": [True, False]}})) == "a[b]=true&a[b]=false" + assert unquote(stringify({"a": {"b": [True, False, None, True]}})) == "a[b]=true&a[b]=false&a[b]=true" + assert unquote(stringify({"in": ["foo", {"b": {"c": ["d", "e"]}}]})) == "in=foo&in[b][c]=d&in[b][c]=e" + + +@pytest.mark.parametrize("method", ["class", "function"]) +def test_array_brackets(method: str) -> None: + if method == "class": + serialise = Querystring(array_format="brackets").stringify + else: + serialise = partial(stringify, array_format="brackets") + + assert unquote(serialise({"in": ["foo", "bar"]})) == "in[]=foo&in[]=bar" + assert unquote(serialise({"a": {"b": [True, False]}})) == "a[b][]=true&a[b][]=false" + assert unquote(serialise({"a": {"b": [True, False, None, True]}})) == "a[b][]=true&a[b][]=false&a[b][]=true" + + +def test_unknown_array_format() -> None: + with pytest.raises(NotImplementedError, match="Unknown array_format value: foo, choose from comma, repeat"): + stringify({"a": ["foo", "bar"]}, array_format=cast(Any, "foo")) diff --git a/tests/test_required_args.py b/tests/test_required_args.py new file mode 100644 index 0000000..84527ed --- /dev/null +++ b/tests/test_required_args.py @@ -0,0 +1,111 @@ +from __future__ import annotations + +import pytest + +from gitpod._utils import required_args + + +def test_too_many_positional_params() -> None: + @required_args(["a"]) + def foo(a: str | None = None) -> str | None: + return a + + with pytest.raises(TypeError, match=r"foo\(\) takes 1 argument\(s\) but 2 were given"): + foo("a", "b") # type: ignore + + +def test_positional_param() -> None: + @required_args(["a"]) + def foo(a: str | None = None) -> str | None: + return a + + assert foo("a") == "a" + assert foo(None) is None + assert foo(a="b") == "b" + + with pytest.raises(TypeError, match="Missing required argument: 'a'"): + foo() + + +def test_keyword_only_param() -> None: + @required_args(["a"]) + def foo(*, a: str | None = None) -> str | None: + return a + + assert foo(a="a") == "a" + assert foo(a=None) is None + assert foo(a="b") == "b" + + with pytest.raises(TypeError, match="Missing required argument: 'a'"): + foo() + + +def test_multiple_params() -> None: + @required_args(["a", "b", "c"]) + def foo(a: str = "", *, b: str = "", c: str = "") -> str | None: + return f"{a} {b} {c}" + + assert foo(a="a", b="b", c="c") == "a b c" + + error_message = r"Missing required arguments.*" + + with pytest.raises(TypeError, match=error_message): + foo() + + with pytest.raises(TypeError, match=error_message): + foo(a="a") + + with pytest.raises(TypeError, match=error_message): + foo(b="b") + + with pytest.raises(TypeError, match=error_message): + foo(c="c") + + with pytest.raises(TypeError, match=r"Missing required argument: 'a'"): + foo(b="a", c="c") + + with pytest.raises(TypeError, match=r"Missing required argument: 'b'"): + foo("a", c="c") + + +def test_multiple_variants() -> None: + @required_args(["a"], ["b"]) + def foo(*, a: str | None = None, b: str | None = None) -> str | None: + return a if a is not None else b + + assert foo(a="foo") == "foo" + assert foo(b="bar") == "bar" + assert foo(a=None) is None + assert foo(b=None) is None + + # TODO: this error message could probably be improved + with pytest.raises( + TypeError, + match=r"Missing required arguments; Expected either \('a'\) or \('b'\) arguments to be given", + ): + foo() + + +def test_multiple_params_multiple_variants() -> None: + @required_args(["a", "b"], ["c"]) + def foo(*, a: str | None = None, b: str | None = None, c: str | None = None) -> str | None: + if a is not None: + return a + if b is not None: + return b + return c + + error_message = r"Missing required arguments; Expected either \('a' and 'b'\) or \('c'\) arguments to be given" + + with pytest.raises(TypeError, match=error_message): + foo(a="foo") + + with pytest.raises(TypeError, match=error_message): + foo(b="bar") + + with pytest.raises(TypeError, match=error_message): + foo() + + assert foo(a=None, b="bar") == "bar" + assert foo(c=None) is None + assert foo(c="foo") == "foo" diff --git a/tests/test_response.py b/tests/test_response.py new file mode 100644 index 0000000..8e6ccd7 --- /dev/null +++ b/tests/test_response.py @@ -0,0 +1,277 @@ +import json +from typing import Any, List, Union, cast +from typing_extensions import Annotated + +import httpx +import pytest +import pydantic + +from gitpod import Gitpod, BaseModel, AsyncGitpod +from gitpod._response import ( + APIResponse, + BaseAPIResponse, + AsyncAPIResponse, + BinaryAPIResponse, + AsyncBinaryAPIResponse, + extract_response_type, +) +from gitpod._streaming import Stream +from gitpod._base_client import FinalRequestOptions + + +class ConcreteBaseAPIResponse(APIResponse[bytes]): ... + + +class ConcreteAPIResponse(APIResponse[List[str]]): ... + + +class ConcreteAsyncAPIResponse(APIResponse[httpx.Response]): ... + + +def test_extract_response_type_direct_classes() -> None: + assert extract_response_type(BaseAPIResponse[str]) == str + assert extract_response_type(APIResponse[str]) == str + assert extract_response_type(AsyncAPIResponse[str]) == str + + +def test_extract_response_type_direct_class_missing_type_arg() -> None: + with pytest.raises( + RuntimeError, + match="Expected type <class 'gitpod._response.AsyncAPIResponse'> to have a type argument at index 0 but it did not", + ): + extract_response_type(AsyncAPIResponse) + + +def test_extract_response_type_concrete_subclasses() -> None: + assert extract_response_type(ConcreteBaseAPIResponse) == bytes + assert extract_response_type(ConcreteAPIResponse) == List[str] + assert extract_response_type(ConcreteAsyncAPIResponse) == httpx.Response + + +def test_extract_response_type_binary_response() -> None: + assert extract_response_type(BinaryAPIResponse) == bytes + assert extract_response_type(AsyncBinaryAPIResponse) == bytes + + +class PydanticModel(pydantic.BaseModel): ... + + +def test_response_parse_mismatched_basemodel(client: Gitpod) -> None: + response = APIResponse( + raw=httpx.Response(200, content=b"foo"), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + with pytest.raises( + TypeError, + match="Pydantic models must subclass our base model type, e.g. `from gitpod import BaseModel`", + ): + response.parse(to=PydanticModel) + + +@pytest.mark.asyncio +async def test_async_response_parse_mismatched_basemodel(async_client: AsyncGitpod) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=b"foo"), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + with pytest.raises( + TypeError, + match="Pydantic models must subclass our base model type, e.g. `from gitpod import BaseModel`", + ): + await response.parse(to=PydanticModel) + + +def test_response_parse_custom_stream(client: Gitpod) -> None: + response = APIResponse( + raw=httpx.Response(200, content=b"foo"), + client=client, + stream=True, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + stream = response.parse(to=Stream[int]) + assert stream._cast_to == int + + +@pytest.mark.asyncio +async def test_async_response_parse_custom_stream(async_client: AsyncGitpod) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=b"foo"), + client=async_client, + stream=True, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + stream = await response.parse(to=Stream[int]) + assert stream._cast_to == int + + +class CustomModel(BaseModel): + foo: str + bar: int + + +def test_response_parse_custom_model(client: Gitpod) -> None: + response = APIResponse( + raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=CustomModel) + assert obj.foo == "hello!" + assert obj.bar == 2 + + +@pytest.mark.asyncio +async def test_async_response_parse_custom_model(async_client: AsyncGitpod) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse(to=CustomModel) + assert obj.foo == "hello!" + assert obj.bar == 2 + + +def test_response_parse_annotated_type(client: Gitpod) -> None: + response = APIResponse( + raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse( + to=cast("type[CustomModel]", Annotated[CustomModel, "random metadata"]), + ) + assert obj.foo == "hello!" + assert obj.bar == 2 + + +async def test_async_response_parse_annotated_type(async_client: AsyncGitpod) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse( + to=cast("type[CustomModel]", Annotated[CustomModel, "random metadata"]), + ) + assert obj.foo == "hello!" + assert obj.bar == 2 + + +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +def test_response_parse_bool(client: Gitpod, content: str, expected: bool) -> None: + response = APIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = response.parse(to=bool) + assert result is expected + + +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +async def test_async_response_parse_bool(client: AsyncGitpod, content: str, expected: bool) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = await response.parse(to=bool) + assert result is expected + + +class OtherModel(BaseModel): + a: str + + +@pytest.mark.parametrize("client", [False], indirect=True) # loose validation +def test_response_parse_expect_model_union_non_json_content(client: Gitpod) -> None: + response = APIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" + + +@pytest.mark.asyncio +@pytest.mark.parametrize("async_client", [False], indirect=True) # loose validation +async def test_async_response_parse_expect_model_union_non_json_content(async_client: AsyncGitpod) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" diff --git a/tests/test_streaming.py b/tests/test_streaming.py new file mode 100644 index 0000000..7dedcf3 --- /dev/null +++ b/tests/test_streaming.py @@ -0,0 +1,248 @@ +from __future__ import annotations + +from typing import Iterator, AsyncIterator + +import httpx +import pytest + +from gitpod import Gitpod, AsyncGitpod +from gitpod._streaming import Stream, AsyncStream, ServerSentEvent + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_basic(sync: bool, client: Gitpod, async_client: AsyncGitpod) -> None: + def body() -> Iterator[bytes]: + yield b"event: completion\n" + yield b'data: {"foo":true}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "completion" + assert sse.json() == {"foo": True} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_data_missing_event(sync: bool, client: Gitpod, async_client: AsyncGitpod) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"foo":true}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"foo": True} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_event_missing_data(sync: bool, client: Gitpod, async_client: AsyncGitpod) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.data == "" + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_events(sync: bool, client: Gitpod, async_client: AsyncGitpod) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"\n" + yield b"event: completion\n" + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.data == "" + + sse = await iter_next(iterator) + assert sse.event == "completion" + assert sse.data == "" + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_events_with_data(sync: bool, client: Gitpod, async_client: AsyncGitpod) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b'data: {"foo":true}\n' + yield b"\n" + yield b"event: completion\n" + yield b'data: {"bar":false}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": True} + + sse = await iter_next(iterator) + assert sse.event == "completion" + assert sse.json() == {"bar": False} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_data_lines_with_empty_line(sync: bool, client: Gitpod, async_client: AsyncGitpod) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"data: {\n" + yield b'data: "foo":\n' + yield b"data: \n" + yield b"data:\n" + yield b"data: true}\n" + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": True} + assert sse.data == '{\n"foo":\n\n\ntrue}' + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_data_json_escaped_double_new_line(sync: bool, client: Gitpod, async_client: AsyncGitpod) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b'data: {"foo": "my long\\n\\ncontent"}' + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": "my long\n\ncontent"} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_data_lines(sync: bool, client: Gitpod, async_client: AsyncGitpod) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"data: {\n" + yield b'data: "foo":\n' + yield b"data: true}\n" + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": True} + + await assert_empty_iter(iterator) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_special_new_line_character( + sync: bool, + client: Gitpod, + async_client: AsyncGitpod, +) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"content":" culpa"}\n' + yield b"\n" + yield b'data: {"content":" \xe2\x80\xa8"}\n' + yield b"\n" + yield b'data: {"content":"foo"}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": " culpa"} + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": " "} + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": "foo"} + + await assert_empty_iter(iterator) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multi_byte_character_multiple_chunks( + sync: bool, + client: Gitpod, + async_client: AsyncGitpod, +) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"content":"' + # bytes taken from the string 'известни' and arbitrarily split + # so that some multi-byte characters span multiple chunks + yield b"\xd0" + yield b"\xb8\xd0\xb7\xd0" + yield b"\xb2\xd0\xb5\xd1\x81\xd1\x82\xd0\xbd\xd0\xb8" + yield b'"}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": "известни"} + + +async def to_aiter(iter: Iterator[bytes]) -> AsyncIterator[bytes]: + for chunk in iter: + yield chunk + + +async def iter_next(iter: Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]) -> ServerSentEvent: + if isinstance(iter, AsyncIterator): + return await iter.__anext__() + + return next(iter) + + +async def assert_empty_iter(iter: Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]) -> None: + with pytest.raises((StopAsyncIteration, RuntimeError)): + await iter_next(iter) + + +def make_event_iterator( + content: Iterator[bytes], + *, + sync: bool, + client: Gitpod, + async_client: AsyncGitpod, +) -> Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]: + if sync: + return Stream(cast_to=object, client=client, response=httpx.Response(200, content=content))._iter_events() + + return AsyncStream( + cast_to=object, client=async_client, response=httpx.Response(200, content=to_aiter(content)) + )._iter_events() diff --git a/tests/test_transform.py b/tests/test_transform.py new file mode 100644 index 0000000..2a74ad4 --- /dev/null +++ b/tests/test_transform.py @@ -0,0 +1,453 @@ +from __future__ import annotations + +import io +import pathlib +from typing import Any, Dict, List, Union, TypeVar, Iterable, Optional, cast +from datetime import date, datetime +from typing_extensions import Required, Annotated, TypedDict + +import pytest + +from gitpod._types import NOT_GIVEN, Base64FileInput +from gitpod._utils import ( + PropertyInfo, + transform as _transform, + parse_datetime, + async_transform as _async_transform, +) +from gitpod._compat import PYDANTIC_V2 +from gitpod._models import BaseModel + +_T = TypeVar("_T") + +SAMPLE_FILE_PATH = pathlib.Path(__file__).parent.joinpath("sample_file.txt") + + +async def transform( + data: _T, + expected_type: object, + use_async: bool, +) -> _T: + if use_async: + return await _async_transform(data, expected_type=expected_type) + + return _transform(data, expected_type=expected_type) + + +parametrize = pytest.mark.parametrize("use_async", [False, True], ids=["sync", "async"]) + + +class Foo1(TypedDict): + foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] + + +@parametrize +@pytest.mark.asyncio +async def test_top_level_alias(use_async: bool) -> None: + assert await transform({"foo_bar": "hello"}, expected_type=Foo1, use_async=use_async) == {"fooBar": "hello"} + + +class Foo2(TypedDict): + bar: Bar2 + + +class Bar2(TypedDict): + this_thing: Annotated[int, PropertyInfo(alias="this__thing")] + baz: Annotated[Baz2, PropertyInfo(alias="Baz")] + + +class Baz2(TypedDict): + my_baz: Annotated[str, PropertyInfo(alias="myBaz")] + + +@parametrize +@pytest.mark.asyncio +async def test_recursive_typeddict(use_async: bool) -> None: + assert await transform({"bar": {"this_thing": 1}}, Foo2, use_async) == {"bar": {"this__thing": 1}} + assert await transform({"bar": {"baz": {"my_baz": "foo"}}}, Foo2, use_async) == {"bar": {"Baz": {"myBaz": "foo"}}} + + +class Foo3(TypedDict): + things: List[Bar3] + + +class Bar3(TypedDict): + my_field: Annotated[str, PropertyInfo(alias="myField")] + + +@parametrize +@pytest.mark.asyncio +async def test_list_of_typeddict(use_async: bool) -> None: + result = await transform({"things": [{"my_field": "foo"}, {"my_field": "foo2"}]}, Foo3, use_async) + assert result == {"things": [{"myField": "foo"}, {"myField": "foo2"}]} + + +class Foo4(TypedDict): + foo: Union[Bar4, Baz4] + + +class Bar4(TypedDict): + foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] + + +class Baz4(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + +@parametrize +@pytest.mark.asyncio +async def test_union_of_typeddict(use_async: bool) -> None: + assert await transform({"foo": {"foo_bar": "bar"}}, Foo4, use_async) == {"foo": {"fooBar": "bar"}} + assert await transform({"foo": {"foo_baz": "baz"}}, Foo4, use_async) == {"foo": {"fooBaz": "baz"}} + assert await transform({"foo": {"foo_baz": "baz", "foo_bar": "bar"}}, Foo4, use_async) == { + "foo": {"fooBaz": "baz", "fooBar": "bar"} + } + + +class Foo5(TypedDict): + foo: Annotated[Union[Bar4, List[Baz4]], PropertyInfo(alias="FOO")] + + +class Bar5(TypedDict): + foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] + + +class Baz5(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + +@parametrize +@pytest.mark.asyncio +async def test_union_of_list(use_async: bool) -> None: + assert await transform({"foo": {"foo_bar": "bar"}}, Foo5, use_async) == {"FOO": {"fooBar": "bar"}} + assert await transform( + { + "foo": [ + {"foo_baz": "baz"}, + {"foo_baz": "baz"}, + ] + }, + Foo5, + use_async, + ) == {"FOO": [{"fooBaz": "baz"}, {"fooBaz": "baz"}]} + + +class Foo6(TypedDict): + bar: Annotated[str, PropertyInfo(alias="Bar")] + + +@parametrize +@pytest.mark.asyncio +async def test_includes_unknown_keys(use_async: bool) -> None: + assert await transform({"bar": "bar", "baz_": {"FOO": 1}}, Foo6, use_async) == { + "Bar": "bar", + "baz_": {"FOO": 1}, + } + + +class Foo7(TypedDict): + bar: Annotated[List[Bar7], PropertyInfo(alias="bAr")] + foo: Bar7 + + +class Bar7(TypedDict): + foo: str + + +@parametrize +@pytest.mark.asyncio +async def test_ignores_invalid_input(use_async: bool) -> None: + assert await transform({"bar": "<foo>"}, Foo7, use_async) == {"bAr": "<foo>"} + assert await transform({"foo": "<foo>"}, Foo7, use_async) == {"foo": "<foo>"} + + +class DatetimeDict(TypedDict, total=False): + foo: Annotated[datetime, PropertyInfo(format="iso8601")] + + bar: Annotated[Optional[datetime], PropertyInfo(format="iso8601")] + + required: Required[Annotated[Optional[datetime], PropertyInfo(format="iso8601")]] + + list_: Required[Annotated[Optional[List[datetime]], PropertyInfo(format="iso8601")]] + + union: Annotated[Union[int, datetime], PropertyInfo(format="iso8601")] + + +class DateDict(TypedDict, total=False): + foo: Annotated[date, PropertyInfo(format="iso8601")] + + +class DatetimeModel(BaseModel): + foo: datetime + + +class DateModel(BaseModel): + foo: Optional[date] + + +@parametrize +@pytest.mark.asyncio +async def test_iso8601_format(use_async: bool) -> None: + dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + tz = "Z" if PYDANTIC_V2 else "+00:00" + assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} # type: ignore[comparison-overlap] + + dt = dt.replace(tzinfo=None) + assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] + + assert await transform({"foo": None}, DateDict, use_async) == {"foo": None} # type: ignore[comparison-overlap] + assert await transform(DateModel(foo=None), Any, use_async) == {"foo": None} # type: ignore + assert await transform({"foo": date.fromisoformat("2023-02-23")}, DateDict, use_async) == {"foo": "2023-02-23"} # type: ignore[comparison-overlap] + assert await transform(DateModel(foo=date.fromisoformat("2023-02-23")), DateDict, use_async) == { + "foo": "2023-02-23" + } # type: ignore[comparison-overlap] + + +@parametrize +@pytest.mark.asyncio +async def test_optional_iso8601_format(use_async: bool) -> None: + dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + assert await transform({"bar": dt}, DatetimeDict, use_async) == {"bar": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] + + assert await transform({"bar": None}, DatetimeDict, use_async) == {"bar": None} + + +@parametrize +@pytest.mark.asyncio +async def test_required_iso8601_format(use_async: bool) -> None: + dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + assert await transform({"required": dt}, DatetimeDict, use_async) == { + "required": "2023-02-23T14:16:36.337692+00:00" + } # type: ignore[comparison-overlap] + + assert await transform({"required": None}, DatetimeDict, use_async) == {"required": None} + + +@parametrize +@pytest.mark.asyncio +async def test_union_datetime(use_async: bool) -> None: + dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + assert await transform({"union": dt}, DatetimeDict, use_async) == { # type: ignore[comparison-overlap] + "union": "2023-02-23T14:16:36.337692+00:00" + } + + assert await transform({"union": "foo"}, DatetimeDict, use_async) == {"union": "foo"} + + +@parametrize +@pytest.mark.asyncio +async def test_nested_list_iso6801_format(use_async: bool) -> None: + dt1 = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + dt2 = parse_datetime("2022-01-15T06:34:23Z") + assert await transform({"list_": [dt1, dt2]}, DatetimeDict, use_async) == { # type: ignore[comparison-overlap] + "list_": ["2023-02-23T14:16:36.337692+00:00", "2022-01-15T06:34:23+00:00"] + } + + +@parametrize +@pytest.mark.asyncio +async def test_datetime_custom_format(use_async: bool) -> None: + dt = parse_datetime("2022-01-15T06:34:23Z") + + result = await transform(dt, Annotated[datetime, PropertyInfo(format="custom", format_template="%H")], use_async) + assert result == "06" # type: ignore[comparison-overlap] + + +class DateDictWithRequiredAlias(TypedDict, total=False): + required_prop: Required[Annotated[date, PropertyInfo(format="iso8601", alias="prop")]] + + +@parametrize +@pytest.mark.asyncio +async def test_datetime_with_alias(use_async: bool) -> None: + assert await transform({"required_prop": None}, DateDictWithRequiredAlias, use_async) == {"prop": None} # type: ignore[comparison-overlap] + assert await transform( + {"required_prop": date.fromisoformat("2023-02-23")}, DateDictWithRequiredAlias, use_async + ) == {"prop": "2023-02-23"} # type: ignore[comparison-overlap] + + +class MyModel(BaseModel): + foo: str + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_model_to_dictionary(use_async: bool) -> None: + assert cast(Any, await transform(MyModel(foo="hi!"), Any, use_async)) == {"foo": "hi!"} + assert cast(Any, await transform(MyModel.construct(foo="hi!"), Any, use_async)) == {"foo": "hi!"} + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_empty_model(use_async: bool) -> None: + assert cast(Any, await transform(MyModel.construct(), Any, use_async)) == {} + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_unknown_field(use_async: bool) -> None: + assert cast(Any, await transform(MyModel.construct(my_untyped_field=True), Any, use_async)) == { + "my_untyped_field": True + } + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_mismatched_types(use_async: bool) -> None: + model = MyModel.construct(foo=True) + if PYDANTIC_V2: + with pytest.warns(UserWarning): + params = await transform(model, Any, use_async) + else: + params = await transform(model, Any, use_async) + assert cast(Any, params) == {"foo": True} + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_mismatched_object_type(use_async: bool) -> None: + model = MyModel.construct(foo=MyModel.construct(hello="world")) + if PYDANTIC_V2: + with pytest.warns(UserWarning): + params = await transform(model, Any, use_async) + else: + params = await transform(model, Any, use_async) + assert cast(Any, params) == {"foo": {"hello": "world"}} + + +class ModelNestedObjects(BaseModel): + nested: MyModel + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_nested_objects(use_async: bool) -> None: + model = ModelNestedObjects.construct(nested={"foo": "stainless"}) + assert isinstance(model.nested, MyModel) + assert cast(Any, await transform(model, Any, use_async)) == {"nested": {"foo": "stainless"}} + + +class ModelWithDefaultField(BaseModel): + foo: str + with_none_default: Union[str, None] = None + with_str_default: str = "foo" + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_default_field(use_async: bool) -> None: + # should be excluded when defaults are used + model = ModelWithDefaultField.construct() + assert model.with_none_default is None + assert model.with_str_default == "foo" + assert cast(Any, await transform(model, Any, use_async)) == {} + + # should be included when the default value is explicitly given + model = ModelWithDefaultField.construct(with_none_default=None, with_str_default="foo") + assert model.with_none_default is None + assert model.with_str_default == "foo" + assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": None, "with_str_default": "foo"} + + # should be included when a non-default value is explicitly given + model = ModelWithDefaultField.construct(with_none_default="bar", with_str_default="baz") + assert model.with_none_default == "bar" + assert model.with_str_default == "baz" + assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": "bar", "with_str_default": "baz"} + + +class TypedDictIterableUnion(TypedDict): + foo: Annotated[Union[Bar8, Iterable[Baz8]], PropertyInfo(alias="FOO")] + + +class Bar8(TypedDict): + foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] + + +class Baz8(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + +@parametrize +@pytest.mark.asyncio +async def test_iterable_of_dictionaries(use_async: bool) -> None: + assert await transform({"foo": [{"foo_baz": "bar"}]}, TypedDictIterableUnion, use_async) == { + "FOO": [{"fooBaz": "bar"}] + } + assert cast(Any, await transform({"foo": ({"foo_baz": "bar"},)}, TypedDictIterableUnion, use_async)) == { + "FOO": [{"fooBaz": "bar"}] + } + + def my_iter() -> Iterable[Baz8]: + yield {"foo_baz": "hello"} + yield {"foo_baz": "world"} + + assert await transform({"foo": my_iter()}, TypedDictIterableUnion, use_async) == { + "FOO": [{"fooBaz": "hello"}, {"fooBaz": "world"}] + } + + +@parametrize +@pytest.mark.asyncio +async def test_dictionary_items(use_async: bool) -> None: + class DictItems(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + assert await transform({"foo": {"foo_baz": "bar"}}, Dict[str, DictItems], use_async) == {"foo": {"fooBaz": "bar"}} + + +class TypedDictIterableUnionStr(TypedDict): + foo: Annotated[Union[str, Iterable[Baz8]], PropertyInfo(alias="FOO")] + + +@parametrize +@pytest.mark.asyncio +async def test_iterable_union_str(use_async: bool) -> None: + assert await transform({"foo": "bar"}, TypedDictIterableUnionStr, use_async) == {"FOO": "bar"} + assert cast(Any, await transform(iter([{"foo_baz": "bar"}]), Union[str, Iterable[Baz8]], use_async)) == [ + {"fooBaz": "bar"} + ] + + +class TypedDictBase64Input(TypedDict): + foo: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] + + +@parametrize +@pytest.mark.asyncio +async def test_base64_file_input(use_async: bool) -> None: + # strings are left as-is + assert await transform({"foo": "bar"}, TypedDictBase64Input, use_async) == {"foo": "bar"} + + # pathlib.Path is automatically converted to base64 + assert await transform({"foo": SAMPLE_FILE_PATH}, TypedDictBase64Input, use_async) == { + "foo": "SGVsbG8sIHdvcmxkIQo=" + } # type: ignore[comparison-overlap] + + # io instances are automatically converted to base64 + assert await transform({"foo": io.StringIO("Hello, world!")}, TypedDictBase64Input, use_async) == { + "foo": "SGVsbG8sIHdvcmxkIQ==" + } # type: ignore[comparison-overlap] + assert await transform({"foo": io.BytesIO(b"Hello, world!")}, TypedDictBase64Input, use_async) == { + "foo": "SGVsbG8sIHdvcmxkIQ==" + } # type: ignore[comparison-overlap] + + +@parametrize +@pytest.mark.asyncio +async def test_transform_skipping(use_async: bool) -> None: + # lists of ints are left as-is + data = [1, 2, 3] + assert await transform(data, List[int], use_async) is data + + # iterables of ints are converted to a list + data = iter([1, 2, 3]) + assert await transform(data, Iterable[int], use_async) == [1, 2, 3] + + +@parametrize +@pytest.mark.asyncio +async def test_strips_notgiven(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": NOT_GIVEN}, Foo1, use_async) == {} diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py new file mode 100644 index 0000000..ec41af2 --- /dev/null +++ b/tests/test_utils/test_proxy.py @@ -0,0 +1,34 @@ +import operator +from typing import Any +from typing_extensions import override + +from gitpod._utils import LazyProxy + + +class RecursiveLazyProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + return self + + def __call__(self, *_args: Any, **_kwds: Any) -> Any: + raise RuntimeError("This should never be called!") + + +def test_recursive_proxy() -> None: + proxy = RecursiveLazyProxy() + assert repr(proxy) == "RecursiveLazyProxy" + assert str(proxy) == "RecursiveLazyProxy" + assert dir(proxy) == [] + assert type(proxy).__name__ == "RecursiveLazyProxy" + assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" + + +def test_isinstance_does_not_error() -> None: + class AlwaysErrorProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + raise RuntimeError("Mocking missing dependency") + + proxy = AlwaysErrorProxy() + assert not isinstance(proxy, dict) + assert isinstance(proxy, LazyProxy) diff --git a/tests/test_utils/test_typing.py b/tests/test_utils/test_typing.py new file mode 100644 index 0000000..18d4ff6 --- /dev/null +++ b/tests/test_utils/test_typing.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +from typing import Generic, TypeVar, cast + +from gitpod._utils import extract_type_var_from_base + +_T = TypeVar("_T") +_T2 = TypeVar("_T2") +_T3 = TypeVar("_T3") + + +class BaseGeneric(Generic[_T]): ... + + +class SubclassGeneric(BaseGeneric[_T]): ... + + +class BaseGenericMultipleTypeArgs(Generic[_T, _T2, _T3]): ... + + +class SubclassGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T, _T2, _T3]): ... + + +class SubclassDifferentOrderGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T2, _T, _T3]): ... + + +def test_extract_type_var() -> None: + assert ( + extract_type_var_from_base( + BaseGeneric[int], + index=0, + generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), + ) + == int + ) + + +def test_extract_type_var_generic_subclass() -> None: + assert ( + extract_type_var_from_base( + SubclassGeneric[int], + index=0, + generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), + ) + == int + ) + + +def test_extract_type_var_multiple() -> None: + typ = BaseGenericMultipleTypeArgs[int, str, None] + + generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) + assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int + assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str + assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) + + +def test_extract_type_var_generic_subclass_multiple() -> None: + typ = SubclassGenericMultipleTypeArgs[int, str, None] + + generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) + assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int + assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str + assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) + + +def test_extract_type_var_generic_subclass_different_ordering_multiple() -> None: + typ = SubclassDifferentOrderGenericMultipleTypeArgs[int, str, None] + + generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) + assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int + assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str + assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..d7dbee6 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +import os +import inspect +import traceback +import contextlib +from typing import Any, TypeVar, Iterator, cast +from datetime import date, datetime +from typing_extensions import Literal, get_args, get_origin, assert_type + +from gitpod._types import Omit, NoneType +from gitpod._utils import ( + is_dict, + is_list, + is_list_type, + is_union_type, + extract_type_arg, + is_annotated_type, + is_type_alias_type, +) +from gitpod._compat import PYDANTIC_V2, field_outer_type, get_model_fields +from gitpod._models import BaseModel + +BaseModelT = TypeVar("BaseModelT", bound=BaseModel) + + +def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: + for name, field in get_model_fields(model).items(): + field_value = getattr(value, name) + if PYDANTIC_V2: + allow_none = False + else: + # in v1 nullability was structured differently + # https://docs.pydantic.dev/2.0/migration/#required-optional-and-nullable-fields + allow_none = getattr(field, "allow_none", False) + + assert_matches_type( + field_outer_type(field), + field_value, + path=[*path, name], + allow_none=allow_none, + ) + + return True + + +# Note: the `path` argument is only used to improve error messages when `--showlocals` is used +def assert_matches_type( + type_: Any, + value: object, + *, + path: list[str], + allow_none: bool = False, +) -> None: + if is_type_alias_type(type_): + type_ = type_.__value__ + + # unwrap `Annotated[T, ...]` -> `T` + if is_annotated_type(type_): + type_ = extract_type_arg(type_, 0) + + if allow_none and value is None: + return + + if type_ is None or type_ is NoneType: + assert value is None + return + + origin = get_origin(type_) or type_ + + if is_list_type(type_): + return _assert_list_type(type_, value) + + if origin == str: + assert isinstance(value, str) + elif origin == int: + assert isinstance(value, int) + elif origin == bool: + assert isinstance(value, bool) + elif origin == float: + assert isinstance(value, float) + elif origin == bytes: + assert isinstance(value, bytes) + elif origin == datetime: + assert isinstance(value, datetime) + elif origin == date: + assert isinstance(value, date) + elif origin == object: + # nothing to do here, the expected type is unknown + pass + elif origin == Literal: + assert value in get_args(type_) + elif origin == dict: + assert is_dict(value) + + args = get_args(type_) + key_type = args[0] + items_type = args[1] + + for key, item in value.items(): + assert_matches_type(key_type, key, path=[*path, "<dict key>"]) + assert_matches_type(items_type, item, path=[*path, "<dict item>"]) + elif is_union_type(type_): + variants = get_args(type_) + + try: + none_index = variants.index(type(None)) + except ValueError: + pass + else: + # special case Optional[T] for better error messages + if len(variants) == 2: + if value is None: + # valid + return + + return assert_matches_type(type_=variants[not none_index], value=value, path=path) + + for i, variant in enumerate(variants): + try: + assert_matches_type(variant, value, path=[*path, f"variant {i}"]) + return + except AssertionError: + traceback.print_exc() + continue + + raise AssertionError("Did not match any variants") + elif issubclass(origin, BaseModel): + assert isinstance(value, type_) + assert assert_matches_model(type_, cast(Any, value), path=path) + elif inspect.isclass(origin) and origin.__name__ == "HttpxBinaryResponseContent": + assert value.__class__.__name__ == "HttpxBinaryResponseContent" + else: + assert None, f"Unhandled field type: {type_}" + + +def _assert_list_type(type_: type[object], value: object) -> None: + assert is_list(value) + + inner_type = get_args(type_)[0] + for entry in value: + assert_type(inner_type, entry) # type: ignore + + +@contextlib.contextmanager +def update_env(**new_env: str | Omit) -> Iterator[None]: + old = os.environ.copy() + + try: + for name, value in new_env.items(): + if isinstance(value, Omit): + os.environ.pop(name, None) + else: + os.environ[name] = value + + yield None + finally: + os.environ.clear() + os.environ.update(old)