diff --git a/.github/workflows/build-binaries.yml b/.github/workflows/build-binaries.yml index decb1e2f..f71952b1 100644 --- a/.github/workflows/build-binaries.yml +++ b/.github/workflows/build-binaries.yml @@ -74,7 +74,26 @@ jobs: - uses: actions/checkout@v6 with: submodules: recursive + - name: "Install fresh upstream rustup" + # The macos-15-arm64 runner image (20260511.0048+) ships a broken + # Homebrew rustup whose bundled rustup-init rejects standard argv + # forwarded from the rustup proxy, breaking `rustup component add` + # and other commands maturin-action invokes. Upstream: + # https://github.com/actions/runner-images/issues/14097 + # Scrub Homebrew's rustup AND any stale upstream rustup, then + # reinstall cleanly with 1.88 as the default so setup-rust-toolchain + # has nothing left to do but verify. + run: | + brew uninstall --ignore-dependencies rustup || true + rm -f "$HOME/.cargo/bin/rustup" "$HOME/.cargo/bin/rustup-init" + curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL https://sh.rustup.rs | sh -s -- --default-toolchain 1.88 --profile minimal -y + echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - uses: actions-rust-lang/setup-rust-toolchain@v1.11.0 + with: + # Don't restore ~/.cargo/bin from cache — it'd clobber the + # freshly-installed upstream rustup with a stale (and possibly + # Homebrew-linked) binary from a previous run. + cache-bin: false - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -102,7 +121,26 @@ jobs: - uses: actions/checkout@v6 with: submodules: recursive + - name: "Install fresh upstream rustup" + # The macos-15-arm64 runner image (20260511.0048+) ships a broken + # Homebrew rustup whose bundled rustup-init rejects standard argv + # forwarded from the rustup proxy, breaking `rustup component add` + # and other commands maturin-action invokes. Upstream: + # https://github.com/actions/runner-images/issues/14097 + # Scrub Homebrew's rustup AND any stale upstream rustup, then + # reinstall cleanly with 1.88 as the default so setup-rust-toolchain + # has nothing left to do but verify. + run: | + brew uninstall --ignore-dependencies rustup || true + rm -f "$HOME/.cargo/bin/rustup" "$HOME/.cargo/bin/rustup-init" + curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL https://sh.rustup.rs | sh -s -- --default-toolchain 1.88 --profile minimal -y + echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - uses: actions-rust-lang/setup-rust-toolchain@v1.11.0 + with: + # Don't restore ~/.cargo/bin from cache — it'd clobber the + # freshly-installed upstream rustup with a stale (and possibly + # Homebrew-linked) binary from a previous run. + cache-bin: false - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -268,16 +306,11 @@ jobs: uses: PyO3/maturin-action@v1.50.1 with: target: ${{ matrix.platform.target }} - manylinux: auto + manylinux: 2_28 docker-options: ${{ matrix.platform.maturin_docker_options }} args: --release --locked --out dist -i python3.10 python3.11 python3.12 python3.13 python3.14 env: CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse - # Set the CFLAGS for the aarch64 target, defining the ARM architecture - # for the ring crate's build script. This is a workaround for the - # issue where the ring crate's build script is not able to detect the - # ARM architecture. - CFLAGS_aarch64_unknown_linux_gnu: "-march=armv8-a -D__ARM_ARCH=8" - uses: uraimo/run-on-arch-action@v2 if: ${{ matrix.platform.arch != 'ppc64' && matrix.platform.arch != 'ppc64le'}} name: Test wheel diff --git a/Cargo.lock b/Cargo.lock index 4238e116..d86231b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -200,6 +200,28 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-rs" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "axum" version = "0.8.4" @@ -342,6 +364,8 @@ version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -463,6 +487,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -491,7 +524,7 @@ dependencies = [ [[package]] name = "config" -version = "0.3.61" +version = "0.3.62" dependencies = [ "base64", "chrono", @@ -598,7 +631,7 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto" -version = "0.3.61" +version = "0.3.62" dependencies = [ "aes-gcm", "base64", @@ -898,6 +931,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "dyn-clone" version = "1.0.19" @@ -1023,6 +1062,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" version = "0.3.31" @@ -1148,10 +1193,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi 0.11.1+wasi-snapshot-preview1", - "wasm-bindgen", ] [[package]] @@ -1161,11 +1204,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi", "wasi 0.14.2+wasi-0.2.4", - "wasm-bindgen", ] [[package]] @@ -1656,6 +1697,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -1761,12 +1812,6 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - [[package]] name = "maplit" version = "1.0.2" @@ -2297,61 +2342,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "quinn" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2 0.5.10", - "thiserror 2.0.12", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" -dependencies = [ - "bytes", - "getrandom 0.3.3", - "lru-slab", - "rand 0.9.2", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.12", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.5.10", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "quote" version = "1.0.40" @@ -2556,7 +2546,6 @@ dependencies = [ "mime_guess", "percent-encoding", "pin-project-lite", - "quinn", "rustls", "rustls-pki-types", "serde", @@ -2698,12 +2687,6 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustix" version = "0.38.44" @@ -2736,8 +2719,8 @@ version = "0.23.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" dependencies = [ + "aws-lc-rs", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -2750,7 +2733,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ - "web-time", "zeroize", ] @@ -2760,6 +2742,7 @@ version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -3348,7 +3331,7 @@ dependencies = [ [[package]] name = "testutils" -version = "0.3.61" +version = "0.3.62" dependencies = [ "pem", "rsa", @@ -3455,21 +3438,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tinyvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tmpdir" version = "1.0.0" @@ -3618,7 +3586,7 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tower" -version = "0.3.61" +version = "0.3.62" dependencies = [ "config", "pyo3", @@ -3646,7 +3614,7 @@ dependencies = [ [[package]] name = "tower-api" -version = "0.3.61" +version = "0.3.62" dependencies = [ "reqwest", "serde", @@ -3658,7 +3626,7 @@ dependencies = [ [[package]] name = "tower-cmd" -version = "0.3.61" +version = "0.3.62" dependencies = [ "axum", "bytes", @@ -3680,6 +3648,7 @@ dependencies = [ "rmcp", "rpassword", "rsa", + "rustls", "schemars 1.0.4", "serde", "serde_json", @@ -3728,7 +3697,7 @@ checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-package" -version = "0.3.61" +version = "0.3.62" dependencies = [ "async-compression", "flate2", @@ -3752,11 +3721,12 @@ dependencies = [ [[package]] name = "tower-runtime" -version = "0.3.61" +version = "0.3.62" dependencies = [ "async-trait", "chrono", "config", + "futures", "nix 0.30.1", "snafu", "tmpdir", @@ -3775,7 +3745,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tower-telemetry" -version = "0.3.61" +version = "0.3.62" dependencies = [ "tracing", "tracing-appender", @@ -3784,7 +3754,7 @@ dependencies = [ [[package]] name = "tower-uv" -version = "0.3.61" +version = "0.3.62" dependencies = [ "async-compression", "async_zip", @@ -3794,6 +3764,7 @@ dependencies = [ "hex", "regex", "reqwest", + "rustls", "seahash", "tempfile", "tokio", @@ -3803,7 +3774,7 @@ dependencies = [ [[package]] name = "tower-version" -version = "0.3.61" +version = "0.3.62" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index a59a228d..cddd184b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ resolver = "2" [workspace.package] edition = "2021" -version = "0.3.61" +version = "0.3.62" description = "Tower is the best way to host Python data apps in production" rust-version = "1.81" authors = ["Brad Heller ", "Ben Lovell "] @@ -43,8 +43,9 @@ pyo3 = { version = "0.28", features = ["extension-module"] } promptly = "0.3" rand = "0.8" regex = "1" -reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "stream"] } +reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls-webpki-roots-no-provider", "stream"] } reqwest-eventsource = { version = "0.6" } +rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs", "std", "tls12"] } rpassword = "7" rsa = "0.9" seahash = "4.1" diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index cca17e88..2e4a48a2 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -26,8 +26,27 @@ pub struct Config { // cache_dir is the directory that we should cache uv artifacts within. pub cache_dir: Option, + + // Override for the page size used when fetching paginated list endpoints. + // None means use the built-in default. + #[serde(skip_serializing, skip_deserializing)] + pub page_size: Option, + + // When false, only the first page of paginated endpoints is fetched. + #[serde(skip_serializing, skip_deserializing)] + pub paginate: bool, + + // Hard upper bound on the number of items returned by a paginated list call. + #[serde(skip_serializing, skip_deserializing)] + pub max_items: Option, + + // Starting page (0-indexed) for paginated list calls. + #[serde(skip_serializing, skip_deserializing)] + pub page: Option, } +pub const DEFAULT_PAGE_SIZE: i64 = 100; + impl Config { pub fn default() -> Self { Self { @@ -37,9 +56,17 @@ impl Config { session: None, api_key: None, cache_dir: Some(default_cache_dir()), + page_size: None, + paginate: true, + max_items: None, + page: None, } } + pub fn page_size(&self) -> i64 { + self.page_size.unwrap_or(DEFAULT_PAGE_SIZE) + } + pub fn from_env() -> Self { let debug = std::env::var("TOWER_DEBUG").is_ok(); let tower_url = if let Some(url) = std::env::var("TOWER_URL").ok() { @@ -56,6 +83,10 @@ impl Config { session: None, api_key, cache_dir: Some(default_cache_dir()), + page_size: None, + paginate: true, + max_items: None, + page: None, } } @@ -74,6 +105,22 @@ impl Config { config.tower_url = Url::parse(tower_url).unwrap(); } + if let Some(page_size) = matches.get_one::("page_size") { + config.page_size = Some(*page_size); + } + + if matches.get_flag("no_paginate") { + config.paginate = false; + } + + if let Some(max_items) = matches.get_one::("max_items") { + config.max_items = Some(*max_items); + } + + if let Some(page) = matches.get_one::("page") { + config.page = Some(*page); + } + config } @@ -85,6 +132,10 @@ impl Config { session: Some(sess), api_key: self.api_key, cache_dir: Some(default_cache_dir()), + page_size: self.page_size, + paginate: self.paginate, + max_items: self.max_items, + page: self.page, } } diff --git a/crates/tower-api/Cargo.toml b/crates/tower-api/Cargo.toml index 9e3f300c..fc43f0a0 100644 --- a/crates/tower-api/Cargo.toml +++ b/crates/tower-api/Cargo.toml @@ -12,4 +12,4 @@ serde_with = { version = "^3.8", default-features = false, features = ["base64", serde_json = "^1.0" serde_repr = "^0.1" url = "^2.5" -reqwest = { version = "^0.12", default-features = false, features = ["json", "multipart", "rustls-tls"] } +reqwest = { version = "^0.12", default-features = false, features = ["json", "multipart", "rustls-tls-webpki-roots-no-provider"] } diff --git a/crates/tower-api/README.md b/crates/tower-api/README.md index cf17a590..34128aec 100644 --- a/crates/tower-api/README.md +++ b/crates/tower-api/README.md @@ -8,7 +8,7 @@ For more information, please visit [https://tower.dev](https://tower.dev) This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://openapis.org) from a remote server, you can easily generate an API client. -- API version: v0.10.17 +- API version: v0.10.24 - Package version: 1.0.0 - Generator version: 7.19.0 - Build package: `org.openapitools.codegen.languages.RustClientCodegen` @@ -36,12 +36,10 @@ Class | Method | HTTP request | Description *DefaultApi* | [**create_account**](docs/DefaultApi.md#create_account) | **POST** /accounts | Create account *DefaultApi* | [**create_api_key**](docs/DefaultApi.md#create_api_key) | **POST** /api-keys | Create API Key *DefaultApi* | [**create_app**](docs/DefaultApi.md#create_app) | **POST** /apps | Create app -*DefaultApi* | [**create_authenticator**](docs/DefaultApi.md#create_authenticator) | **POST** /authenticators | Create authenticator *DefaultApi* | [**create_catalog**](docs/DefaultApi.md#create_catalog) | **POST** /catalogs | Create catalog *DefaultApi* | [**create_device_login_ticket**](docs/DefaultApi.md#create_device_login_ticket) | **GET** /login/device | Create device login ticket *DefaultApi* | [**create_environment**](docs/DefaultApi.md#create_environment) | **POST** /environments | Create environment *DefaultApi* | [**create_guest**](docs/DefaultApi.md#create_guest) | **POST** /guests | Create guest -*DefaultApi* | [**create_password_reset**](docs/DefaultApi.md#create_password_reset) | **POST** /accounts/password-reset | Create password reset *DefaultApi* | [**create_sandbox_secrets**](docs/DefaultApi.md#create_sandbox_secrets) | **POST** /sandbox/secrets | Create Tower-provided sandbox secrets *DefaultApi* | [**create_schedule**](docs/DefaultApi.md#create_schedule) | **POST** /schedules | Create schedule *DefaultApi* | [**create_secret**](docs/DefaultApi.md#create_secret) | **POST** /secrets | Create secret @@ -52,7 +50,6 @@ Class | Method | HTTP request | Description *DefaultApi* | [**delete_alert**](docs/DefaultApi.md#delete_alert) | **DELETE** /alerts/{alert_id} | Delete alert *DefaultApi* | [**delete_api_key**](docs/DefaultApi.md#delete_api_key) | **DELETE** /api-keys | Delete API key *DefaultApi* | [**delete_app**](docs/DefaultApi.md#delete_app) | **DELETE** /apps/{name} | Delete app -*DefaultApi* | [**delete_authenticator**](docs/DefaultApi.md#delete_authenticator) | **DELETE** /authenticators | Delete authenticator *DefaultApi* | [**delete_catalog**](docs/DefaultApi.md#delete_catalog) | **DELETE** /catalogs/{name} | Delete catalog *DefaultApi* | [**delete_guest**](docs/DefaultApi.md#delete_guest) | **DELETE** /guests/{guest_id} | Delete guest *DefaultApi* | [**delete_schedule**](docs/DefaultApi.md#delete_schedule) | **DELETE** /schedules | Delete schedule @@ -81,7 +78,7 @@ Class | Method | HTTP request | Description *DefaultApi* | [**export_catalogs**](docs/DefaultApi.md#export_catalogs) | **POST** /catalogs/export | Export catalogs *DefaultApi* | [**export_secrets**](docs/DefaultApi.md#export_secrets) | **POST** /secrets/export | Export secrets *DefaultApi* | [**generate_app_statistics**](docs/DefaultApi.md#generate_app_statistics) | **GET** /stats/apps | Generate app statistics -*DefaultApi* | [**generate_authenticator**](docs/DefaultApi.md#generate_authenticator) | **POST** /authenticators/generate | Generate authenticator +*DefaultApi* | [**generate_organization_usage_time_series**](docs/DefaultApi.md#generate_organization_usage_time_series) | **GET** /usage/time-series | Get organization usage as time series *DefaultApi* | [**generate_run_statistics**](docs/DefaultApi.md#generate_run_statistics) | **GET** /stats/runs | Generate run statistics *DefaultApi* | [**generate_runner_credentials**](docs/DefaultApi.md#generate_runner_credentials) | **POST** /runners/credentials | Generate runner credentials *DefaultApi* | [**invite_team_member**](docs/DefaultApi.md#invite_team_member) | **POST** /teams/{name}/invites | Invite team member @@ -91,7 +88,6 @@ Class | Method | HTTP request | Description *DefaultApi* | [**list_app_environments**](docs/DefaultApi.md#list_app_environments) | **GET** /apps/{name}/environments | List app environments *DefaultApi* | [**list_app_versions**](docs/DefaultApi.md#list_app_versions) | **GET** /apps/{name}/versions | List app versions *DefaultApi* | [**list_apps**](docs/DefaultApi.md#list_apps) | **GET** /apps | List apps -*DefaultApi* | [**list_authenticators**](docs/DefaultApi.md#list_authenticators) | **GET** /authenticators | List authenticators *DefaultApi* | [**list_catalogs**](docs/DefaultApi.md#list_catalogs) | **GET** /catalogs | List catalogs *DefaultApi* | [**list_environments**](docs/DefaultApi.md#list_environments) | **GET** /environments | List environments *DefaultApi* | [**list_guests**](docs/DefaultApi.md#list_guests) | **GET** /guests | List guests @@ -108,7 +104,6 @@ Class | Method | HTTP request | Description *DefaultApi* | [**refresh_session**](docs/DefaultApi.md#refresh_session) | **POST** /session/refresh | Refresh session *DefaultApi* | [**regenerate_guest_login_url**](docs/DefaultApi.md#regenerate_guest_login_url) | **POST** /guests/{guest_id}/login-url | Regenerate guest login URL *DefaultApi* | [**remove_team_member**](docs/DefaultApi.md#remove_team_member) | **DELETE** /teams/{name}/members | Remove team member -*DefaultApi* | [**resend_email_verification**](docs/DefaultApi.md#resend_email_verification) | **POST** /user/resend-verification | Resent email verification *DefaultApi* | [**resend_team_invitation**](docs/DefaultApi.md#resend_team_invitation) | **POST** /teams/{name}/invites/resend | Resend team invitation *DefaultApi* | [**run_app**](docs/DefaultApi.md#run_app) | **POST** /apps/{name}/runs | Run app *DefaultApi* | [**search_runs**](docs/DefaultApi.md#search_runs) | **GET** /runs | Search runs @@ -117,12 +112,12 @@ Class | Method | HTTP request | Description *DefaultApi* | [**stream_shouldertaps**](docs/DefaultApi.md#stream_shouldertaps) | **GET** /shouldertaps/stream | Stream shouldertaps *DefaultApi* | [**update_account**](docs/DefaultApi.md#update_account) | **PUT** /accounts/{name} | Update account *DefaultApi* | [**update_app**](docs/DefaultApi.md#update_app) | **PUT** /apps/{name} | Update app +*DefaultApi* | [**update_app_environment**](docs/DefaultApi.md#update_app_environment) | **PUT** /apps/{name}/environments/{environment} | Update app environment *DefaultApi* | [**update_catalog**](docs/DefaultApi.md#update_catalog) | **PUT** /catalogs/{name} | Update catalog *DefaultApi* | [**update_email_preferences**](docs/DefaultApi.md#update_email_preferences) | **PUT** /user/email-preferences | Update email preferences *DefaultApi* | [**update_environment**](docs/DefaultApi.md#update_environment) | **PUT** /environments/{name} | Update environment *DefaultApi* | [**update_my_team_invitation**](docs/DefaultApi.md#update_my_team_invitation) | **PUT** /team-invites | Update my team invitation *DefaultApi* | [**update_organization**](docs/DefaultApi.md#update_organization) | **PUT** /organizations/{name} | Update organization -*DefaultApi* | [**update_password_reset**](docs/DefaultApi.md#update_password_reset) | **POST** /accounts/password-reset/{code} | Update password reset *DefaultApi* | [**update_plan**](docs/DefaultApi.md#update_plan) | **PUT** /plan | Update plan *DefaultApi* | [**update_schedule**](docs/DefaultApi.md#update_schedule) | **PUT** /schedules/{idOrName} | Update schedule *DefaultApi* | [**update_secret**](docs/DefaultApi.md#update_secret) | **PUT** /secrets/{name} | Update secret @@ -130,7 +125,6 @@ Class | Method | HTTP request | Description *DefaultApi* | [**update_team_member**](docs/DefaultApi.md#update_team_member) | **PUT** /teams/{name}/members | Update team member *DefaultApi* | [**update_user**](docs/DefaultApi.md#update_user) | **PUT** /user | Update user profile *DefaultApi* | [**update_webhook**](docs/DefaultApi.md#update_webhook) | **PUT** /webhooks/{name} | Update webhook -*DefaultApi* | [**verify_email**](docs/DefaultApi.md#verify_email) | **POST** /user/verify | Verify email *FeatureFlagsApi* | [**get_feature_flag_value**](docs/FeatureFlagsApi.md#get_feature_flag_value) | **GET** /feature-flags/{key} | Get feature flag value @@ -160,8 +154,6 @@ Class | Method | HTTP request | Description - [CreateApiKeyResponse](docs/CreateApiKeyResponse.md) - [CreateAppParams](docs/CreateAppParams.md) - [CreateAppResponse](docs/CreateAppResponse.md) - - [CreateAuthenticatorParams](docs/CreateAuthenticatorParams.md) - - [CreateAuthenticatorResponse](docs/CreateAuthenticatorResponse.md) - [CreateCatalogParams](docs/CreateCatalogParams.md) - [CreateCatalogResponse](docs/CreateCatalogResponse.md) - [CreateDeviceLoginTicketResponse](docs/CreateDeviceLoginTicketResponse.md) @@ -169,8 +161,6 @@ Class | Method | HTTP request | Description - [CreateEnvironmentResponse](docs/CreateEnvironmentResponse.md) - [CreateGuestParams](docs/CreateGuestParams.md) - [CreateGuestResponse](docs/CreateGuestResponse.md) - - [CreatePasswordResetParams](docs/CreatePasswordResetParams.md) - - [CreatePasswordResetResponse](docs/CreatePasswordResetResponse.md) - [CreateSandboxSecretsParams](docs/CreateSandboxSecretsParams.md) - [CreateSandboxSecretsResponse](docs/CreateSandboxSecretsResponse.md) - [CreateScheduleParams](docs/CreateScheduleParams.md) @@ -186,8 +176,6 @@ Class | Method | HTTP request | Description - [DeleteApiKeyParams](docs/DeleteApiKeyParams.md) - [DeleteApiKeyResponse](docs/DeleteApiKeyResponse.md) - [DeleteAppResponse](docs/DeleteAppResponse.md) - - [DeleteAuthenticatorParams](docs/DeleteAuthenticatorParams.md) - - [DeleteAuthenticatorResponse](docs/DeleteAuthenticatorResponse.md) - [DeleteCatalogResponse](docs/DeleteCatalogResponse.md) - [DeleteGuestOutputBody](docs/DeleteGuestOutputBody.md) - [DeleteScheduleParams](docs/DeleteScheduleParams.md) @@ -238,7 +226,7 @@ Class | Method | HTTP request | Description - [Feature](docs/Feature.md) - [FeaturebaseIdentity](docs/FeaturebaseIdentity.md) - [GenerateAppStatisticsResponse](docs/GenerateAppStatisticsResponse.md) - - [GenerateAuthenticatorResponse](docs/GenerateAuthenticatorResponse.md) + - [GenerateOrganizationUsageTimeSeriesResponse](docs/GenerateOrganizationUsageTimeSeriesResponse.md) - [GenerateRunStatisticsResponse](docs/GenerateRunStatisticsResponse.md) - [GenerateRunnerCredentialsResponse](docs/GenerateRunnerCredentialsResponse.md) - [GetFeatureFlagResponseBody](docs/GetFeatureFlagResponseBody.md) @@ -251,7 +239,6 @@ Class | Method | HTTP request | Description - [ListAppEnvironmentsResponse](docs/ListAppEnvironmentsResponse.md) - [ListAppVersionsResponse](docs/ListAppVersionsResponse.md) - [ListAppsResponse](docs/ListAppsResponse.md) - - [ListAuthenticatorsResponse](docs/ListAuthenticatorsResponse.md) - [ListCatalogsResponse](docs/ListCatalogsResponse.md) - [ListEnvironmentsResponse](docs/ListEnvironmentsResponse.md) - [ListGuestsResponse](docs/ListGuestsResponse.md) @@ -313,9 +300,10 @@ Class | Method | HTTP request | Description - [TeamMembership](docs/TeamMembership.md) - [TestWebhookResponse](docs/TestWebhookResponse.md) - [Token](docs/Token.md) - - [UnverifiedAuthenticator](docs/UnverifiedAuthenticator.md) - [UpdateAccountParams](docs/UpdateAccountParams.md) - [UpdateAccountResponse](docs/UpdateAccountResponse.md) + - [UpdateAppEnvironmentParams](docs/UpdateAppEnvironmentParams.md) + - [UpdateAppEnvironmentResponse](docs/UpdateAppEnvironmentResponse.md) - [UpdateAppParams](docs/UpdateAppParams.md) - [UpdateAppResponse](docs/UpdateAppResponse.md) - [UpdateCatalogParams](docs/UpdateCatalogParams.md) @@ -327,8 +315,6 @@ Class | Method | HTTP request | Description - [UpdateMyTeamInvitationResponse](docs/UpdateMyTeamInvitationResponse.md) - [UpdateOrganizationParams](docs/UpdateOrganizationParams.md) - [UpdateOrganizationResponse](docs/UpdateOrganizationResponse.md) - - [UpdatePasswordResetParams](docs/UpdatePasswordResetParams.md) - - [UpdatePasswordResetResponse](docs/UpdatePasswordResetResponse.md) - [UpdatePlanParams](docs/UpdatePlanParams.md) - [UpdatePlanResponse](docs/UpdatePlanResponse.md) - [UpdateScheduleParams](docs/UpdateScheduleParams.md) @@ -344,10 +330,8 @@ Class | Method | HTTP request | Description - [UpdateWebhookParams](docs/UpdateWebhookParams.md) - [UpdateWebhookResponse](docs/UpdateWebhookResponse.md) - [UsageLimit](docs/UsageLimit.md) + - [UsageMetricTimeSeriesPoint](docs/UsageMetricTimeSeriesPoint.md) - [User](docs/User.md) - - [VerifiedAuthenticator](docs/VerifiedAuthenticator.md) - - [VerifyEmailParams](docs/VerifyEmailParams.md) - - [VerifyEmailResponse](docs/VerifyEmailResponse.md) - [Webhook](docs/Webhook.md) diff --git a/crates/tower-api/src/apis/configuration.rs b/crates/tower-api/src/apis/configuration.rs index 2fb4a64e..8c0cc1d9 100644 --- a/crates/tower-api/src/apis/configuration.rs +++ b/crates/tower-api/src/apis/configuration.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/apis/default_api.rs b/crates/tower-api/src/apis/default_api.rs index d80db99c..3b081631 100644 --- a/crates/tower-api/src/apis/default_api.rs +++ b/crates/tower-api/src/apis/default_api.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -67,12 +67,6 @@ pub struct CreateAppParams { pub create_app_params: models::CreateAppParams, } -/// struct for passing parameters to the method [`create_authenticator`] -#[derive(Clone, Debug)] -pub struct CreateAuthenticatorParams { - pub create_authenticator_params: models::CreateAuthenticatorParams, -} - /// struct for passing parameters to the method [`create_catalog`] #[derive(Clone, Debug)] pub struct CreateCatalogParams { @@ -91,12 +85,6 @@ pub struct CreateGuestParams { pub create_guest_params: models::CreateGuestParams, } -/// struct for passing parameters to the method [`create_password_reset`] -#[derive(Clone, Debug)] -pub struct CreatePasswordResetParams { - pub create_password_reset_params: models::CreatePasswordResetParams, -} - /// struct for passing parameters to the method [`create_sandbox_secrets`] #[derive(Clone, Debug)] pub struct CreateSandboxSecretsParams { @@ -159,12 +147,6 @@ pub struct DeleteAppParams { pub name: String, } -/// struct for passing parameters to the method [`delete_authenticator`] -#[derive(Clone, Debug)] -pub struct DeleteAuthenticatorParams { - pub delete_authenticator_params: models::DeleteAuthenticatorParams, -} - /// struct for passing parameters to the method [`delete_catalog`] #[derive(Clone, Debug)] pub struct DeleteCatalogParams { @@ -234,6 +216,10 @@ pub struct DeployAppParams { pub x_tower_checksum_sha256: Option, /// Size of the uploaded bundle in bytes. pub content_length: Option, + /// The environment to deploy to. + pub environment: Option, + /// Whether to deploy to all environments for this app. If true, the 'environment' query parameter is ignored. + pub all_environments: Option, } /// struct for passing parameters to the method [`describe_account`] @@ -256,6 +242,8 @@ pub struct DescribeAppParams { pub end_at: Option, /// Timezone for the statistics (e.g., 'Europe/Berlin'). Defaults to UTC. pub timezone: Option, + /// The environment to resolve the app version against. Defaults to 'default'. + pub environment: Option, } /// struct for passing parameters to the method [`describe_app_version`] @@ -645,6 +633,16 @@ pub struct UpdateAppParams { pub update_app_params: models::UpdateAppParams, } +/// struct for passing parameters to the method [`update_app_environment`] +#[derive(Clone, Debug)] +pub struct UpdateAppEnvironmentParams { + /// The name of the app. + pub name: String, + /// The name of the environment. + pub environment: String, + pub update_app_environment_params: models::UpdateAppEnvironmentParams, +} + /// struct for passing parameters to the method [`update_catalog`] #[derive(Clone, Debug)] pub struct UpdateCatalogParams { @@ -681,14 +679,6 @@ pub struct UpdateOrganizationParams { pub update_organization_params: models::UpdateOrganizationParams, } -/// struct for passing parameters to the method [`update_password_reset`] -#[derive(Clone, Debug)] -pub struct UpdatePasswordResetParams { - /// The password reset code that was sent to you - pub code: String, - pub update_password_reset_params: models::UpdatePasswordResetParams, -} - /// struct for passing parameters to the method [`update_plan`] #[derive(Clone, Debug)] pub struct UpdatePlanParams { @@ -740,12 +730,6 @@ pub struct UpdateWebhookParams { pub update_webhook_params: models::UpdateWebhookParams, } -/// struct for passing parameters to the method [`verify_email`] -#[derive(Clone, Debug)] -pub struct VerifyEmailParams { - pub verify_email_params: models::VerifyEmailParams, -} - /// struct for typed successes of method [`acknowledge_alert`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -818,14 +802,6 @@ pub enum CreateAppSuccess { UnknownValue(serde_json::Value), } -/// struct for typed successes of method [`create_authenticator`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum CreateAuthenticatorSuccess { - Status200(models::CreateAuthenticatorResponse), - UnknownValue(serde_json::Value), -} - /// struct for typed successes of method [`create_catalog`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -858,14 +834,6 @@ pub enum CreateGuestSuccess { UnknownValue(serde_json::Value), } -/// struct for typed successes of method [`create_password_reset`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum CreatePasswordResetSuccess { - Status200(models::CreatePasswordResetResponse), - UnknownValue(serde_json::Value), -} - /// struct for typed successes of method [`create_sandbox_secrets`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -946,14 +914,6 @@ pub enum DeleteAppSuccess { UnknownValue(serde_json::Value), } -/// struct for typed successes of method [`delete_authenticator`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum DeleteAuthenticatorSuccess { - Status200(models::DeleteAuthenticatorResponse), - UnknownValue(serde_json::Value), -} - /// struct for typed successes of method [`delete_catalog`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1178,11 +1138,11 @@ pub enum GenerateAppStatisticsSuccess { UnknownValue(serde_json::Value), } -/// struct for typed successes of method [`generate_authenticator`] +/// struct for typed successes of method [`generate_organization_usage_time_series`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] -pub enum GenerateAuthenticatorSuccess { - Status200(models::GenerateAuthenticatorResponse), +pub enum GenerateOrganizationUsageTimeSeriesSuccess { + Status200(models::GenerateOrganizationUsageTimeSeriesResponse), UnknownValue(serde_json::Value), } @@ -1258,14 +1218,6 @@ pub enum ListAppsSuccess { UnknownValue(serde_json::Value), } -/// struct for typed successes of method [`list_authenticators`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ListAuthenticatorsSuccess { - Status200(models::ListAuthenticatorsResponse), - UnknownValue(serde_json::Value), -} - /// struct for typed successes of method [`list_catalogs`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1394,14 +1346,6 @@ pub enum RemoveTeamMemberSuccess { UnknownValue(serde_json::Value), } -/// struct for typed successes of method [`resend_email_verification`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ResendEmailVerificationSuccess { - Status204(), - UnknownValue(serde_json::Value), -} - /// struct for typed successes of method [`resend_team_invitation`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1466,6 +1410,14 @@ pub enum UpdateAppSuccess { UnknownValue(serde_json::Value), } +/// struct for typed successes of method [`update_app_environment`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum UpdateAppEnvironmentSuccess { + Status200(models::UpdateAppEnvironmentResponse), + UnknownValue(serde_json::Value), +} + /// struct for typed successes of method [`update_catalog`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1506,14 +1458,6 @@ pub enum UpdateOrganizationSuccess { UnknownValue(serde_json::Value), } -/// struct for typed successes of method [`update_password_reset`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum UpdatePasswordResetSuccess { - Status200(models::UpdatePasswordResetResponse), - UnknownValue(serde_json::Value), -} - /// struct for typed successes of method [`update_plan`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1570,14 +1514,6 @@ pub enum UpdateWebhookSuccess { UnknownValue(serde_json::Value), } -/// struct for typed successes of method [`verify_email`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum VerifyEmailSuccess { - Status200(models::VerifyEmailResponse), - UnknownValue(serde_json::Value), -} - /// struct for typed errors of method [`acknowledge_alert`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1650,14 +1586,6 @@ pub enum CreateAppError { UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`create_authenticator`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum CreateAuthenticatorError { - DefaultResponse(models::ErrorModel), - UnknownValue(serde_json::Value), -} - /// struct for typed errors of method [`create_catalog`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1690,14 +1618,6 @@ pub enum CreateGuestError { UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`create_password_reset`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum CreatePasswordResetError { - DefaultResponse(models::ErrorModel), - UnknownValue(serde_json::Value), -} - /// struct for typed errors of method [`create_sandbox_secrets`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1781,14 +1701,6 @@ pub enum DeleteAppError { UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`delete_authenticator`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum DeleteAuthenticatorError { - DefaultResponse(models::ErrorModel), - UnknownValue(serde_json::Value), -} - /// struct for typed errors of method [`delete_catalog`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -2017,10 +1929,10 @@ pub enum GenerateAppStatisticsError { UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`generate_authenticator`] +/// struct for typed errors of method [`generate_organization_usage_time_series`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] -pub enum GenerateAuthenticatorError { +pub enum GenerateOrganizationUsageTimeSeriesError { DefaultResponse(models::ErrorModel), UnknownValue(serde_json::Value), } @@ -2097,14 +2009,6 @@ pub enum ListAppsError { UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`list_authenticators`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ListAuthenticatorsError { - DefaultResponse(models::ErrorModel), - UnknownValue(serde_json::Value), -} - /// struct for typed errors of method [`list_catalogs`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -2233,14 +2137,6 @@ pub enum RemoveTeamMemberError { UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`resend_email_verification`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ResendEmailVerificationError { - DefaultResponse(models::ErrorModel), - UnknownValue(serde_json::Value), -} - /// struct for typed errors of method [`resend_team_invitation`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -2305,6 +2201,14 @@ pub enum UpdateAppError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`update_app_environment`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum UpdateAppEnvironmentError { + DefaultResponse(models::ErrorModel), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`update_catalog`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -2351,14 +2255,6 @@ pub enum UpdateOrganizationError { UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`update_password_reset`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum UpdatePasswordResetError { - DefaultResponse(models::ErrorModel), - UnknownValue(serde_json::Value), -} - /// struct for typed errors of method [`update_plan`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -2415,14 +2311,6 @@ pub enum UpdateWebhookError { UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`verify_email`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum VerifyEmailError { - DefaultResponse(models::ErrorModel), - UnknownValue(serde_json::Value), -} - /// Mark an alert as acknowledged pub async fn acknowledge_alert( configuration: &configuration::Configuration, @@ -2940,64 +2828,6 @@ pub async fn create_app( } } -/// Associates an authenticator with your account, where the authenticator is identified by the URL with an otpauth URI scheme. -pub async fn create_authenticator( - configuration: &configuration::Configuration, - params: CreateAuthenticatorParams, -) -> Result, Error> { - let uri_str = format!("{}/authenticators", configuration.base_path); - let mut req_builder = configuration - .client - .request(reqwest::Method::POST, &uri_str); - - if let Some(ref user_agent) = configuration.user_agent { - req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); - } - if let Some(ref token) = configuration.bearer_access_token { - req_builder = req_builder.bearer_auth(token.to_owned()); - }; - if let Some(ref apikey) = configuration.api_key { - let key = apikey.key.clone(); - let value = match apikey.prefix { - Some(ref prefix) => format!("{} {}", prefix, key), - None => key, - }; - req_builder = req_builder.header("X-API-Key", value); - }; - req_builder = req_builder.json(¶ms.create_authenticator_params); - - let req = req_builder.build()?; - let resp = configuration.client.execute(req).await?; - - let status = resp.status(); - - let tower_trace_id = resp - .headers() - .get("x-tower-trace-id") - .and_then(|v| v.to_str().ok()) - .map_or(String::from(DEFAULT_TOWER_TRACE_ID), String::from); - - if !status.is_client_error() && !status.is_server_error() { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Ok(ResponseContent { - tower_trace_id, - status, - content, - entity, - }) - } else { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Err(Error::ResponseError(ResponseContent { - tower_trace_id, - status, - content, - entity, - })) - } -} - /// Create a new catalog object in the currently authenticated account. pub async fn create_catalog( configuration: &configuration::Configuration, @@ -3215,53 +3045,6 @@ pub async fn create_guest( } } -/// Starts the password reset process for an account. If an email address exists for the account supplied, you will get a reset password email. -pub async fn create_password_reset( - configuration: &configuration::Configuration, - params: CreatePasswordResetParams, -) -> Result, Error> { - let uri_str = format!("{}/accounts/password-reset", configuration.base_path); - let mut req_builder = configuration - .client - .request(reqwest::Method::POST, &uri_str); - - if let Some(ref user_agent) = configuration.user_agent { - req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); - } - req_builder = req_builder.json(¶ms.create_password_reset_params); - - let req = req_builder.build()?; - let resp = configuration.client.execute(req).await?; - - let status = resp.status(); - - let tower_trace_id = resp - .headers() - .get("x-tower-trace-id") - .and_then(|v| v.to_str().ok()) - .map_or(String::from(DEFAULT_TOWER_TRACE_ID), String::from); - - if !status.is_client_error() && !status.is_server_error() { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Ok(ResponseContent { - tower_trace_id, - status, - content, - entity, - }) - } else { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Err(Error::ResponseError(ResponseContent { - tower_trace_id, - status, - content, - entity, - })) - } -} - /// Creates secrets with Tower-provided default values for the specified keys in the given environment. pub async fn create_sandbox_secrets( configuration: &configuration::Configuration, @@ -3835,64 +3618,6 @@ pub async fn delete_app( } } -/// Removes an authenticator from your account so you're no longer required to provide it at login. -pub async fn delete_authenticator( - configuration: &configuration::Configuration, - params: DeleteAuthenticatorParams, -) -> Result, Error> { - let uri_str = format!("{}/authenticators", configuration.base_path); - let mut req_builder = configuration - .client - .request(reqwest::Method::DELETE, &uri_str); - - if let Some(ref user_agent) = configuration.user_agent { - req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); - } - if let Some(ref token) = configuration.bearer_access_token { - req_builder = req_builder.bearer_auth(token.to_owned()); - }; - if let Some(ref apikey) = configuration.api_key { - let key = apikey.key.clone(); - let value = match apikey.prefix { - Some(ref prefix) => format!("{} {}", prefix, key), - None => key, - }; - req_builder = req_builder.header("X-API-Key", value); - }; - req_builder = req_builder.json(¶ms.delete_authenticator_params); - - let req = req_builder.build()?; - let resp = configuration.client.execute(req).await?; - - let status = resp.status(); - - let tower_trace_id = resp - .headers() - .get("x-tower-trace-id") - .and_then(|v| v.to_str().ok()) - .map_or(String::from(DEFAULT_TOWER_TRACE_ID), String::from); - - if !status.is_client_error() && !status.is_server_error() { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Ok(ResponseContent { - tower_trace_id, - status, - content, - entity, - }) - } else { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Err(Error::ResponseError(ResponseContent { - tower_trace_id, - status, - content, - entity, - })) - } -} - /// Delete a new catalog object in the currently authenticated account. pub async fn delete_catalog( configuration: &configuration::Configuration, @@ -4392,6 +4117,12 @@ pub async fn deploy_app( .client .request(reqwest::Method::POST, &uri_str); + if let Some(ref param_value) = params.environment { + req_builder = req_builder.query(&[("environment", ¶m_value.to_string())]); + } + if let Some(ref param_value) = params.all_environments { + req_builder = req_builder.query(&[("all_environments", ¶m_value.to_string())]); + } if let Some(ref user_agent) = configuration.user_agent { req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); } @@ -4529,6 +4260,9 @@ pub async fn describe_app( if let Some(ref param_value) = params.timezone { req_builder = req_builder.query(&[("timezone", ¶m_value.to_string())]); } + if let Some(ref param_value) = params.environment { + req_builder = req_builder.query(&[("environment", ¶m_value.to_string())]); + } if let Some(ref user_agent) = configuration.user_agent { req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); } @@ -4863,7 +4597,7 @@ pub async fn describe_email_preferences( } } -/// Describe usage statistics for the user's organization. +/// Describe usage statistics for the user's organization for the current billing cycle. pub async fn describe_organization_usage( configuration: &configuration::Configuration, ) -> Result, Error> @@ -5565,14 +5299,15 @@ pub async fn generate_app_statistics( } } -/// Generates a new authenticator for the user. This is used to set up two-factor authentication. -pub async fn generate_authenticator( +/// Get the current billing cycle usage as a time series. +pub async fn generate_organization_usage_time_series( configuration: &configuration::Configuration, -) -> Result, Error> { - let uri_str = format!("{}/authenticators/generate", configuration.base_path); - let mut req_builder = configuration - .client - .request(reqwest::Method::POST, &uri_str); +) -> Result< + ResponseContent, + Error, +> { + let uri_str = format!("{}/usage/time-series", configuration.base_path); + let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); if let Some(ref user_agent) = configuration.user_agent { req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); @@ -5602,7 +5337,8 @@ pub async fn generate_authenticator( if !status.is_client_error() && !status.is_server_error() { let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); + let entity: Option = + serde_json::from_str(&content).ok(); Ok(ResponseContent { tower_trace_id, status, @@ -5611,7 +5347,8 @@ pub async fn generate_authenticator( }) } else { let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); + let entity: Option = + serde_json::from_str(&content).ok(); Err(Error::ResponseError(ResponseContent { tower_trace_id, status, @@ -6214,60 +5951,6 @@ pub async fn list_apps( } } -/// Enumerates the authenticators associated with the current users' account -pub async fn list_authenticators( - configuration: &configuration::Configuration, -) -> Result, Error> { - let uri_str = format!("{}/authenticators", configuration.base_path); - let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str); - - if let Some(ref user_agent) = configuration.user_agent { - req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); - } - if let Some(ref token) = configuration.bearer_access_token { - req_builder = req_builder.bearer_auth(token.to_owned()); - }; - if let Some(ref apikey) = configuration.api_key { - let key = apikey.key.clone(); - let value = match apikey.prefix { - Some(ref prefix) => format!("{} {}", prefix, key), - None => key, - }; - req_builder = req_builder.header("X-API-Key", value); - }; - - let req = req_builder.build()?; - let resp = configuration.client.execute(req).await?; - - let status = resp.status(); - - let tower_trace_id = resp - .headers() - .get("x-tower-trace-id") - .and_then(|v| v.to_str().ok()) - .map_or(String::from(DEFAULT_TOWER_TRACE_ID), String::from); - - if !status.is_client_error() && !status.is_server_error() { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Ok(ResponseContent { - tower_trace_id, - status, - content, - entity, - }) - } else { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Err(Error::ResponseError(ResponseContent { - tower_trace_id, - status, - content, - entity, - })) - } -} - /// Lists all the catalogs associated with your current account. pub async fn list_catalogs( configuration: &configuration::Configuration, @@ -7267,62 +6950,6 @@ pub async fn remove_team_member( } } -/// If a user doesn't have a verified email address, this API endpoint will send a new confirmation email to them -pub async fn resend_email_verification( - configuration: &configuration::Configuration, -) -> Result, Error> { - let uri_str = format!("{}/user/resend-verification", configuration.base_path); - let mut req_builder = configuration - .client - .request(reqwest::Method::POST, &uri_str); - - if let Some(ref user_agent) = configuration.user_agent { - req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); - } - if let Some(ref token) = configuration.bearer_access_token { - req_builder = req_builder.bearer_auth(token.to_owned()); - }; - if let Some(ref apikey) = configuration.api_key { - let key = apikey.key.clone(); - let value = match apikey.prefix { - Some(ref prefix) => format!("{} {}", prefix, key), - None => key, - }; - req_builder = req_builder.header("X-API-Key", value); - }; - - let req = req_builder.build()?; - let resp = configuration.client.execute(req).await?; - - let status = resp.status(); - - let tower_trace_id = resp - .headers() - .get("x-tower-trace-id") - .and_then(|v| v.to_str().ok()) - .map_or(String::from(DEFAULT_TOWER_TRACE_ID), String::from); - - if !status.is_client_error() && !status.is_server_error() { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Ok(ResponseContent { - tower_trace_id, - status, - content, - entity, - }) - } else { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Err(Error::ResponseError(ResponseContent { - tower_trace_id, - status, - content, - entity, - })) - } -} - /// Resend a team invitation to a user if they need a reminder or if they lost it pub async fn resend_team_invitation( configuration: &configuration::Configuration, @@ -7824,6 +7451,67 @@ pub async fn update_app( } } +/// Update the configuration of an app in a specific environment, such as which version is deployed. +pub async fn update_app_environment( + configuration: &configuration::Configuration, + params: UpdateAppEnvironmentParams, +) -> Result, Error> { + let uri_str = format!( + "{}/apps/{name}/environments/{environment}", + configuration.base_path, + name = crate::apis::urlencode(params.name), + environment = crate::apis::urlencode(params.environment) + ); + let mut req_builder = configuration.client.request(reqwest::Method::PUT, &uri_str); + + if let Some(ref user_agent) = configuration.user_agent { + req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); + } + if let Some(ref token) = configuration.bearer_access_token { + req_builder = req_builder.bearer_auth(token.to_owned()); + }; + if let Some(ref apikey) = configuration.api_key { + let key = apikey.key.clone(); + let value = match apikey.prefix { + Some(ref prefix) => format!("{} {}", prefix, key), + None => key, + }; + req_builder = req_builder.header("X-API-Key", value); + }; + req_builder = req_builder.json(¶ms.update_app_environment_params); + + let req = req_builder.build()?; + let resp = configuration.client.execute(req).await?; + + let status = resp.status(); + + let tower_trace_id = resp + .headers() + .get("x-tower-trace-id") + .and_then(|v| v.to_str().ok()) + .map_or(String::from(DEFAULT_TOWER_TRACE_ID), String::from); + + if !status.is_client_error() && !status.is_server_error() { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Ok(ResponseContent { + tower_trace_id, + status, + content, + entity, + }) + } else { + let content = resp.text().await?; + let entity: Option = serde_json::from_str(&content).ok(); + Err(Error::ResponseError(ResponseContent { + tower_trace_id, + status, + content, + entity, + })) + } +} + /// Update a new catalog object in the currently authenticated account. pub async fn update_catalog( configuration: &configuration::Configuration, @@ -8116,57 +7804,6 @@ pub async fn update_organization( } } -/// Updates the password reset code with the new password -pub async fn update_password_reset( - configuration: &configuration::Configuration, - params: UpdatePasswordResetParams, -) -> Result, Error> { - let uri_str = format!( - "{}/accounts/password-reset/{code}", - configuration.base_path, - code = crate::apis::urlencode(params.code) - ); - let mut req_builder = configuration - .client - .request(reqwest::Method::POST, &uri_str); - - if let Some(ref user_agent) = configuration.user_agent { - req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); - } - req_builder = req_builder.json(¶ms.update_password_reset_params); - - let req = req_builder.build()?; - let resp = configuration.client.execute(req).await?; - - let status = resp.status(); - - let tower_trace_id = resp - .headers() - .get("x-tower-trace-id") - .and_then(|v| v.to_str().ok()) - .map_or(String::from(DEFAULT_TOWER_TRACE_ID), String::from); - - if !status.is_client_error() && !status.is_server_error() { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Ok(ResponseContent { - tower_trace_id, - status, - content, - entity, - }) - } else { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Err(Error::ResponseError(ResponseContent { - tower_trace_id, - status, - content, - entity, - })) - } -} - pub async fn update_plan( configuration: &configuration::Configuration, params: UpdatePlanParams, @@ -8576,61 +8213,3 @@ pub async fn update_webhook( })) } } - -/// If the user hasn't verified their email address, this API endpoint allows them to send a confirmation token they received via email to indeed verify they can receive emails. -pub async fn verify_email( - configuration: &configuration::Configuration, - params: VerifyEmailParams, -) -> Result, Error> { - let uri_str = format!("{}/user/verify", configuration.base_path); - let mut req_builder = configuration - .client - .request(reqwest::Method::POST, &uri_str); - - if let Some(ref user_agent) = configuration.user_agent { - req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); - } - if let Some(ref token) = configuration.bearer_access_token { - req_builder = req_builder.bearer_auth(token.to_owned()); - }; - if let Some(ref apikey) = configuration.api_key { - let key = apikey.key.clone(); - let value = match apikey.prefix { - Some(ref prefix) => format!("{} {}", prefix, key), - None => key, - }; - req_builder = req_builder.header("X-API-Key", value); - }; - req_builder = req_builder.json(¶ms.verify_email_params); - - let req = req_builder.build()?; - let resp = configuration.client.execute(req).await?; - - let status = resp.status(); - - let tower_trace_id = resp - .headers() - .get("x-tower-trace-id") - .and_then(|v| v.to_str().ok()) - .map_or(String::from(DEFAULT_TOWER_TRACE_ID), String::from); - - if !status.is_client_error() && !status.is_server_error() { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Ok(ResponseContent { - tower_trace_id, - status, - content, - entity, - }) - } else { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Err(Error::ResponseError(ResponseContent { - tower_trace_id, - status, - content, - entity, - })) - } -} diff --git a/crates/tower-api/src/apis/feature_flags_api.rs b/crates/tower-api/src/apis/feature_flags_api.rs index df1a7e95..1e9a0237 100644 --- a/crates/tower-api/src/apis/feature_flags_api.rs +++ b/crates/tower-api/src/apis/feature_flags_api.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/account.rs b/crates/tower-api/src/models/account.rs index 6bc16d2f..116672a5 100644 --- a/crates/tower-api/src/models/account.rs +++ b/crates/tower-api/src/models/account.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/acknowledge_alert_response.rs b/crates/tower-api/src/models/acknowledge_alert_response.rs index 69a4d41e..3cf58938 100644 --- a/crates/tower-api/src/models/acknowledge_alert_response.rs +++ b/crates/tower-api/src/models/acknowledge_alert_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/acknowledge_all_alerts_response.rs b/crates/tower-api/src/models/acknowledge_all_alerts_response.rs index 0d7abb66..91060002 100644 --- a/crates/tower-api/src/models/acknowledge_all_alerts_response.rs +++ b/crates/tower-api/src/models/acknowledge_all_alerts_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/alert.rs b/crates/tower-api/src/models/alert.rs index 1d0a28f6..16e47b0c 100644 --- a/crates/tower-api/src/models/alert.rs +++ b/crates/tower-api/src/models/alert.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/api_key.rs b/crates/tower-api/src/models/api_key.rs index a6ef1419..1f112ff5 100644 --- a/crates/tower-api/src/models/api_key.rs +++ b/crates/tower-api/src/models/api_key.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/app.rs b/crates/tower-api/src/models/app.rs index e13daf09..abbc4c54 100644 --- a/crates/tower-api/src/models/app.rs +++ b/crates/tower-api/src/models/app.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/app_statistics.rs b/crates/tower-api/src/models/app_statistics.rs index ea5e9193..f2d9c680 100644 --- a/crates/tower-api/src/models/app_statistics.rs +++ b/crates/tower-api/src/models/app_statistics.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/app_summary.rs b/crates/tower-api/src/models/app_summary.rs index 1cc996c9..a2eb79df 100644 --- a/crates/tower-api/src/models/app_summary.rs +++ b/crates/tower-api/src/models/app_summary.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/app_version.rs b/crates/tower-api/src/models/app_version.rs index 7fed8482..d1262e21 100644 --- a/crates/tower-api/src/models/app_version.rs +++ b/crates/tower-api/src/models/app_version.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/authentication_context.rs b/crates/tower-api/src/models/authentication_context.rs index db0ea04f..ba6f7a8b 100644 --- a/crates/tower-api/src/models/authentication_context.rs +++ b/crates/tower-api/src/models/authentication_context.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/batch_schedule_params.rs b/crates/tower-api/src/models/batch_schedule_params.rs index 6283b874..54d803d5 100644 --- a/crates/tower-api/src/models/batch_schedule_params.rs +++ b/crates/tower-api/src/models/batch_schedule_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/batch_schedule_response.rs b/crates/tower-api/src/models/batch_schedule_response.rs index 3bbfeb99..95604266 100644 --- a/crates/tower-api/src/models/batch_schedule_response.rs +++ b/crates/tower-api/src/models/batch_schedule_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/cancel_run_response.rs b/crates/tower-api/src/models/cancel_run_response.rs index 49769543..07da93b7 100644 --- a/crates/tower-api/src/models/cancel_run_response.rs +++ b/crates/tower-api/src/models/cancel_run_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -17,13 +17,21 @@ pub struct CancelRunResponse { /// A URL to the JSON Schema for this object. #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")] pub schema: Option, + /// Number of descendant runs that were also cancelled as part of this cascade. + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "cancelled_child_runs")] + pub cancelled_child_runs: i64, #[serde_as(as = "DefaultOnNull")] #[serde(rename = "run")] pub run: models::Run, } impl CancelRunResponse { - pub fn new(run: models::Run) -> CancelRunResponse { - CancelRunResponse { schema: None, run } + pub fn new(cancelled_child_runs: i64, run: models::Run) -> CancelRunResponse { + CancelRunResponse { + schema: None, + cancelled_child_runs, + run, + } } } diff --git a/crates/tower-api/src/models/catalog.rs b/crates/tower-api/src/models/catalog.rs index 47c54003..cfc5944f 100644 --- a/crates/tower-api/src/models/catalog.rs +++ b/crates/tower-api/src/models/catalog.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/catalog_property.rs b/crates/tower-api/src/models/catalog_property.rs index 89ecb996..708c9a98 100644 --- a/crates/tower-api/src/models/catalog_property.rs +++ b/crates/tower-api/src/models/catalog_property.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/claim_device_login_ticket_params.rs b/crates/tower-api/src/models/claim_device_login_ticket_params.rs index 1513f934..4571e526 100644 --- a/crates/tower-api/src/models/claim_device_login_ticket_params.rs +++ b/crates/tower-api/src/models/claim_device_login_ticket_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/claim_device_login_ticket_response.rs b/crates/tower-api/src/models/claim_device_login_ticket_response.rs index 8d90761f..c671b5eb 100644 --- a/crates/tower-api/src/models/claim_device_login_ticket_response.rs +++ b/crates/tower-api/src/models/claim_device_login_ticket_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_account_params.rs b/crates/tower-api/src/models/create_account_params.rs index 84a22a12..336e8686 100644 --- a/crates/tower-api/src/models/create_account_params.rs +++ b/crates/tower-api/src/models/create_account_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_account_params_flags_struct.rs b/crates/tower-api/src/models/create_account_params_flags_struct.rs index d5ed4904..328e26c0 100644 --- a/crates/tower-api/src/models/create_account_params_flags_struct.rs +++ b/crates/tower-api/src/models/create_account_params_flags_struct.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_account_response.rs b/crates/tower-api/src/models/create_account_response.rs index 16828667..1ea4ae6c 100644 --- a/crates/tower-api/src/models/create_account_response.rs +++ b/crates/tower-api/src/models/create_account_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_api_key_params.rs b/crates/tower-api/src/models/create_api_key_params.rs index 582d9b5f..2530d81d 100644 --- a/crates/tower-api/src/models/create_api_key_params.rs +++ b/crates/tower-api/src/models/create_api_key_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_api_key_response.rs b/crates/tower-api/src/models/create_api_key_response.rs index d7bacc8f..d30a2857 100644 --- a/crates/tower-api/src/models/create_api_key_response.rs +++ b/crates/tower-api/src/models/create_api_key_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_app_params.rs b/crates/tower-api/src/models/create_app_params.rs index b49de310..4e988c8f 100644 --- a/crates/tower-api/src/models/create_app_params.rs +++ b/crates/tower-api/src/models/create_app_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_app_response.rs b/crates/tower-api/src/models/create_app_response.rs index 36d1f4b7..cd76db8f 100644 --- a/crates/tower-api/src/models/create_app_response.rs +++ b/crates/tower-api/src/models/create_app_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_catalog_params.rs b/crates/tower-api/src/models/create_catalog_params.rs index a48906ae..6d68e41e 100644 --- a/crates/tower-api/src/models/create_catalog_params.rs +++ b/crates/tower-api/src/models/create_catalog_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -60,6 +60,8 @@ pub enum Type { Lakekeeper, #[serde(rename = "tower-catalog")] TowerCatalog, + #[serde(rename = "s3-tables")] + S3Tables, } impl Default for Type { @@ -80,6 +82,7 @@ impl<'de> Deserialize<'de> for Type { "cloudflare-r2-catalog" => Ok(Self::CloudflareR2Catalog), "lakekeeper" => Ok(Self::Lakekeeper), "tower-catalog" => Ok(Self::TowerCatalog), + "s3-tables" => Ok(Self::S3Tables), _ => Err(serde::de::Error::unknown_variant( &s, &[ @@ -88,6 +91,7 @@ impl<'de> Deserialize<'de> for Type { "cloudflare-r2-catalog", "lakekeeper", "tower-catalog", + "s3-tables", ], )), } diff --git a/crates/tower-api/src/models/create_catalog_response.rs b/crates/tower-api/src/models/create_catalog_response.rs index 1b7feab8..b18d7639 100644 --- a/crates/tower-api/src/models/create_catalog_response.rs +++ b/crates/tower-api/src/models/create_catalog_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_device_login_ticket_response.rs b/crates/tower-api/src/models/create_device_login_ticket_response.rs index cf2cdf04..8ed291d2 100644 --- a/crates/tower-api/src/models/create_device_login_ticket_response.rs +++ b/crates/tower-api/src/models/create_device_login_ticket_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_environment_params.rs b/crates/tower-api/src/models/create_environment_params.rs index 985bfd26..7f5841f2 100644 --- a/crates/tower-api/src/models/create_environment_params.rs +++ b/crates/tower-api/src/models/create_environment_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_environment_response.rs b/crates/tower-api/src/models/create_environment_response.rs index b92f1e3d..d6b5d4ac 100644 --- a/crates/tower-api/src/models/create_environment_response.rs +++ b/crates/tower-api/src/models/create_environment_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_guest_params.rs b/crates/tower-api/src/models/create_guest_params.rs index 1d929417..6d24139a 100644 --- a/crates/tower-api/src/models/create_guest_params.rs +++ b/crates/tower-api/src/models/create_guest_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_guest_response.rs b/crates/tower-api/src/models/create_guest_response.rs index 797cf9d9..efaa7b59 100644 --- a/crates/tower-api/src/models/create_guest_response.rs +++ b/crates/tower-api/src/models/create_guest_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_sandbox_secrets_params.rs b/crates/tower-api/src/models/create_sandbox_secrets_params.rs index 1cec5160..ff6cc634 100644 --- a/crates/tower-api/src/models/create_sandbox_secrets_params.rs +++ b/crates/tower-api/src/models/create_sandbox_secrets_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_sandbox_secrets_response.rs b/crates/tower-api/src/models/create_sandbox_secrets_response.rs index 85969a9b..afeb5d6b 100644 --- a/crates/tower-api/src/models/create_sandbox_secrets_response.rs +++ b/crates/tower-api/src/models/create_sandbox_secrets_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_schedule_params.rs b/crates/tower-api/src/models/create_schedule_params.rs index f1f7b453..a87807d0 100644 --- a/crates/tower-api/src/models/create_schedule_params.rs +++ b/crates/tower-api/src/models/create_schedule_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -21,7 +21,7 @@ pub struct CreateScheduleParams { #[serde_as(as = "DefaultOnNull")] #[serde(rename = "app_name")] pub app_name: String, - /// The specific app version to run (if omitted, will use the app's default version) + /// This property is deprecated and ignored. Schedules inherit the version from their environment. #[serde( rename = "app_version", default, diff --git a/crates/tower-api/src/models/create_schedule_response.rs b/crates/tower-api/src/models/create_schedule_response.rs index a10c413e..f2746869 100644 --- a/crates/tower-api/src/models/create_schedule_response.rs +++ b/crates/tower-api/src/models/create_schedule_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_secret_params.rs b/crates/tower-api/src/models/create_secret_params.rs index 695f87d7..d074ecf0 100644 --- a/crates/tower-api/src/models/create_secret_params.rs +++ b/crates/tower-api/src/models/create_secret_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_secret_response.rs b/crates/tower-api/src/models/create_secret_response.rs index 613dfc98..6e67efbe 100644 --- a/crates/tower-api/src/models/create_secret_response.rs +++ b/crates/tower-api/src/models/create_secret_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_session_params.rs b/crates/tower-api/src/models/create_session_params.rs index dca56e2b..f911bb0e 100644 --- a/crates/tower-api/src/models/create_session_params.rs +++ b/crates/tower-api/src/models/create_session_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_session_response.rs b/crates/tower-api/src/models/create_session_response.rs index fb8368b2..1b522b5b 100644 --- a/crates/tower-api/src/models/create_session_response.rs +++ b/crates/tower-api/src/models/create_session_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_team_params.rs b/crates/tower-api/src/models/create_team_params.rs index 9c8d77f3..6b1df789 100644 --- a/crates/tower-api/src/models/create_team_params.rs +++ b/crates/tower-api/src/models/create_team_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_team_response.rs b/crates/tower-api/src/models/create_team_response.rs index 45004172..a4641a5f 100644 --- a/crates/tower-api/src/models/create_team_response.rs +++ b/crates/tower-api/src/models/create_team_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_webhook_params.rs b/crates/tower-api/src/models/create_webhook_params.rs index 613a2a42..2efa854f 100644 --- a/crates/tower-api/src/models/create_webhook_params.rs +++ b/crates/tower-api/src/models/create_webhook_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/create_webhook_response.rs b/crates/tower-api/src/models/create_webhook_response.rs index a558436e..905ee30e 100644 --- a/crates/tower-api/src/models/create_webhook_response.rs +++ b/crates/tower-api/src/models/create_webhook_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_api_key_params.rs b/crates/tower-api/src/models/delete_api_key_params.rs index ceea7328..08b09485 100644 --- a/crates/tower-api/src/models/delete_api_key_params.rs +++ b/crates/tower-api/src/models/delete_api_key_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_api_key_response.rs b/crates/tower-api/src/models/delete_api_key_response.rs index dd5042f6..6532f3c0 100644 --- a/crates/tower-api/src/models/delete_api_key_response.rs +++ b/crates/tower-api/src/models/delete_api_key_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_app_response.rs b/crates/tower-api/src/models/delete_app_response.rs index 6ad3f4e4..23ee6d59 100644 --- a/crates/tower-api/src/models/delete_app_response.rs +++ b/crates/tower-api/src/models/delete_app_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_catalog_response.rs b/crates/tower-api/src/models/delete_catalog_response.rs index 94a6436f..1eab81e6 100644 --- a/crates/tower-api/src/models/delete_catalog_response.rs +++ b/crates/tower-api/src/models/delete_catalog_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_guest_output_body.rs b/crates/tower-api/src/models/delete_guest_output_body.rs index 494227a2..4cad97b8 100644 --- a/crates/tower-api/src/models/delete_guest_output_body.rs +++ b/crates/tower-api/src/models/delete_guest_output_body.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_schedule_params.rs b/crates/tower-api/src/models/delete_schedule_params.rs index 4cbe866b..7ac3e40a 100644 --- a/crates/tower-api/src/models/delete_schedule_params.rs +++ b/crates/tower-api/src/models/delete_schedule_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_schedule_response.rs b/crates/tower-api/src/models/delete_schedule_response.rs index 5a145359..2bb66758 100644 --- a/crates/tower-api/src/models/delete_schedule_response.rs +++ b/crates/tower-api/src/models/delete_schedule_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_secret_response.rs b/crates/tower-api/src/models/delete_secret_response.rs index 13f0c7a5..6b243271 100644 --- a/crates/tower-api/src/models/delete_secret_response.rs +++ b/crates/tower-api/src/models/delete_secret_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_session_params.rs b/crates/tower-api/src/models/delete_session_params.rs index 02e2b3dc..68502ec9 100644 --- a/crates/tower-api/src/models/delete_session_params.rs +++ b/crates/tower-api/src/models/delete_session_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_session_response.rs b/crates/tower-api/src/models/delete_session_response.rs index 66eeb6cb..fd2a8cca 100644 --- a/crates/tower-api/src/models/delete_session_response.rs +++ b/crates/tower-api/src/models/delete_session_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_team_invitation_params.rs b/crates/tower-api/src/models/delete_team_invitation_params.rs index edf7fb18..e3612231 100644 --- a/crates/tower-api/src/models/delete_team_invitation_params.rs +++ b/crates/tower-api/src/models/delete_team_invitation_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_team_invitation_response.rs b/crates/tower-api/src/models/delete_team_invitation_response.rs index e86f224f..8c158558 100644 --- a/crates/tower-api/src/models/delete_team_invitation_response.rs +++ b/crates/tower-api/src/models/delete_team_invitation_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_team_params.rs b/crates/tower-api/src/models/delete_team_params.rs index d67705a1..68d0be3d 100644 --- a/crates/tower-api/src/models/delete_team_params.rs +++ b/crates/tower-api/src/models/delete_team_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_team_response.rs b/crates/tower-api/src/models/delete_team_response.rs index 04902420..0231e905 100644 --- a/crates/tower-api/src/models/delete_team_response.rs +++ b/crates/tower-api/src/models/delete_team_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/delete_webhook_response.rs b/crates/tower-api/src/models/delete_webhook_response.rs index 327a4fc4..f7988d8b 100644 --- a/crates/tower-api/src/models/delete_webhook_response.rs +++ b/crates/tower-api/src/models/delete_webhook_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/deploy_app_request.rs b/crates/tower-api/src/models/deploy_app_request.rs index 4f7a20d5..0636309a 100644 --- a/crates/tower-api/src/models/deploy_app_request.rs +++ b/crates/tower-api/src/models/deploy_app_request.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/deploy_app_response.rs b/crates/tower-api/src/models/deploy_app_response.rs index a4cb448b..e3000f51 100644 --- a/crates/tower-api/src/models/deploy_app_response.rs +++ b/crates/tower-api/src/models/deploy_app_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_account_body.rs b/crates/tower-api/src/models/describe_account_body.rs index ce51e184..d860bc7b 100644 --- a/crates/tower-api/src/models/describe_account_body.rs +++ b/crates/tower-api/src/models/describe_account_body.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_app_response.rs b/crates/tower-api/src/models/describe_app_response.rs index af78089a..252b611f 100644 --- a/crates/tower-api/src/models/describe_app_response.rs +++ b/crates/tower-api/src/models/describe_app_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_app_version_response.rs b/crates/tower-api/src/models/describe_app_version_response.rs index d7d64477..88011575 100644 --- a/crates/tower-api/src/models/describe_app_version_response.rs +++ b/crates/tower-api/src/models/describe_app_version_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_authentication_context_body.rs b/crates/tower-api/src/models/describe_authentication_context_body.rs index 05c1e4fb..49ae2ae9 100644 --- a/crates/tower-api/src/models/describe_authentication_context_body.rs +++ b/crates/tower-api/src/models/describe_authentication_context_body.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_catalog_response.rs b/crates/tower-api/src/models/describe_catalog_response.rs index 3bf15cf2..131c83ca 100644 --- a/crates/tower-api/src/models/describe_catalog_response.rs +++ b/crates/tower-api/src/models/describe_catalog_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_device_login_session_response.rs b/crates/tower-api/src/models/describe_device_login_session_response.rs index 8b2e870c..9f002161 100644 --- a/crates/tower-api/src/models/describe_device_login_session_response.rs +++ b/crates/tower-api/src/models/describe_device_login_session_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_email_preferences_body.rs b/crates/tower-api/src/models/describe_email_preferences_body.rs index b15f801e..37609c33 100644 --- a/crates/tower-api/src/models/describe_email_preferences_body.rs +++ b/crates/tower-api/src/models/describe_email_preferences_body.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_plan_response.rs b/crates/tower-api/src/models/describe_plan_response.rs index 5028d8db..debd454f 100644 --- a/crates/tower-api/src/models/describe_plan_response.rs +++ b/crates/tower-api/src/models/describe_plan_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_run_graph_response.rs b/crates/tower-api/src/models/describe_run_graph_response.rs index 35c2f7d8..63e9f060 100644 --- a/crates/tower-api/src/models/describe_run_graph_response.rs +++ b/crates/tower-api/src/models/describe_run_graph_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_run_links.rs b/crates/tower-api/src/models/describe_run_links.rs index d676a1f6..508248ce 100644 --- a/crates/tower-api/src/models/describe_run_links.rs +++ b/crates/tower-api/src/models/describe_run_links.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_run_logs_response.rs b/crates/tower-api/src/models/describe_run_logs_response.rs index 3118866b..2abee200 100644 --- a/crates/tower-api/src/models/describe_run_logs_response.rs +++ b/crates/tower-api/src/models/describe_run_logs_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_run_response.rs b/crates/tower-api/src/models/describe_run_response.rs index 081e8721..b14ea569 100644 --- a/crates/tower-api/src/models/describe_run_response.rs +++ b/crates/tower-api/src/models/describe_run_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_secrets_key_response.rs b/crates/tower-api/src/models/describe_secrets_key_response.rs index 16bd9f80..cbf925f0 100644 --- a/crates/tower-api/src/models/describe_secrets_key_response.rs +++ b/crates/tower-api/src/models/describe_secrets_key_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_session_response.rs b/crates/tower-api/src/models/describe_session_response.rs index f52d184f..2d6af965 100644 --- a/crates/tower-api/src/models/describe_session_response.rs +++ b/crates/tower-api/src/models/describe_session_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_team_response.rs b/crates/tower-api/src/models/describe_team_response.rs index a1323547..f866d4eb 100644 --- a/crates/tower-api/src/models/describe_team_response.rs +++ b/crates/tower-api/src/models/describe_team_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/describe_webhook_response.rs b/crates/tower-api/src/models/describe_webhook_response.rs index ef66530c..b38ae16e 100644 --- a/crates/tower-api/src/models/describe_webhook_response.rs +++ b/crates/tower-api/src/models/describe_webhook_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/email_subscriptions.rs b/crates/tower-api/src/models/email_subscriptions.rs index 18d42b2d..63f26c6b 100644 --- a/crates/tower-api/src/models/email_subscriptions.rs +++ b/crates/tower-api/src/models/email_subscriptions.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/encrypted_catalog_property.rs b/crates/tower-api/src/models/encrypted_catalog_property.rs index 227a1afe..ae3bad2a 100644 --- a/crates/tower-api/src/models/encrypted_catalog_property.rs +++ b/crates/tower-api/src/models/encrypted_catalog_property.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/environment.rs b/crates/tower-api/src/models/environment.rs index 3e3ec43b..fca84227 100644 --- a/crates/tower-api/src/models/environment.rs +++ b/crates/tower-api/src/models/environment.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/error_detail.rs b/crates/tower-api/src/models/error_detail.rs index ffc77035..b38f2403 100644 --- a/crates/tower-api/src/models/error_detail.rs +++ b/crates/tower-api/src/models/error_detail.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/error_model.rs b/crates/tower-api/src/models/error_model.rs index 43500163..aad23278 100644 --- a/crates/tower-api/src/models/error_model.rs +++ b/crates/tower-api/src/models/error_model.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/event_alert.rs b/crates/tower-api/src/models/event_alert.rs index a43eb580..2be91340 100644 --- a/crates/tower-api/src/models/event_alert.rs +++ b/crates/tower-api/src/models/event_alert.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/event_error.rs b/crates/tower-api/src/models/event_error.rs index f55f33bb..f7728cc3 100644 --- a/crates/tower-api/src/models/event_error.rs +++ b/crates/tower-api/src/models/event_error.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/event_log.rs b/crates/tower-api/src/models/event_log.rs index 00bc043d..2ddb3bdd 100644 --- a/crates/tower-api/src/models/event_log.rs +++ b/crates/tower-api/src/models/event_log.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/event_shouldertap.rs b/crates/tower-api/src/models/event_shouldertap.rs index 38ab0fd6..ae2d8478 100644 --- a/crates/tower-api/src/models/event_shouldertap.rs +++ b/crates/tower-api/src/models/event_shouldertap.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/event_warning.rs b/crates/tower-api/src/models/event_warning.rs index 12907c95..5bf5d34b 100644 --- a/crates/tower-api/src/models/event_warning.rs +++ b/crates/tower-api/src/models/event_warning.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/export_catalogs_params.rs b/crates/tower-api/src/models/export_catalogs_params.rs index 8e347e07..bb3405be 100644 --- a/crates/tower-api/src/models/export_catalogs_params.rs +++ b/crates/tower-api/src/models/export_catalogs_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/export_catalogs_response.rs b/crates/tower-api/src/models/export_catalogs_response.rs index d2b43036..97e63115 100644 --- a/crates/tower-api/src/models/export_catalogs_response.rs +++ b/crates/tower-api/src/models/export_catalogs_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/export_secrets_params.rs b/crates/tower-api/src/models/export_secrets_params.rs index a74c2ca8..edbbae54 100644 --- a/crates/tower-api/src/models/export_secrets_params.rs +++ b/crates/tower-api/src/models/export_secrets_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/export_secrets_response.rs b/crates/tower-api/src/models/export_secrets_response.rs index 32a1dc7d..3b0abe0e 100644 --- a/crates/tower-api/src/models/export_secrets_response.rs +++ b/crates/tower-api/src/models/export_secrets_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/exported_catalog.rs b/crates/tower-api/src/models/exported_catalog.rs index 24830dd1..487b6316 100644 --- a/crates/tower-api/src/models/exported_catalog.rs +++ b/crates/tower-api/src/models/exported_catalog.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/exported_catalog_property.rs b/crates/tower-api/src/models/exported_catalog_property.rs index c0c8ef2f..d94e101c 100644 --- a/crates/tower-api/src/models/exported_catalog_property.rs +++ b/crates/tower-api/src/models/exported_catalog_property.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/exported_secret.rs b/crates/tower-api/src/models/exported_secret.rs index 3ea9181a..ca789489 100644 --- a/crates/tower-api/src/models/exported_secret.rs +++ b/crates/tower-api/src/models/exported_secret.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/feature.rs b/crates/tower-api/src/models/feature.rs index 8ea4778c..6e5ca4e0 100644 --- a/crates/tower-api/src/models/feature.rs +++ b/crates/tower-api/src/models/feature.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/featurebase_identity.rs b/crates/tower-api/src/models/featurebase_identity.rs index edb77672..faa671c0 100644 --- a/crates/tower-api/src/models/featurebase_identity.rs +++ b/crates/tower-api/src/models/featurebase_identity.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/generate_app_statistics_response.rs b/crates/tower-api/src/models/generate_app_statistics_response.rs index 87930793..f81187c5 100644 --- a/crates/tower-api/src/models/generate_app_statistics_response.rs +++ b/crates/tower-api/src/models/generate_app_statistics_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/generate_organization_usage_time_series_response.rs b/crates/tower-api/src/models/generate_organization_usage_time_series_response.rs new file mode 100644 index 00000000..68ea2be1 --- /dev/null +++ b/crates/tower-api/src/models/generate_organization_usage_time_series_response.rs @@ -0,0 +1,34 @@ +/* + * Tower API + * + * REST API to interact with Tower Services. + * + * The version of the OpenAPI document: v0.10.24 + * Contact: hello@tower.dev + * Generated by: https://openapi-generator.tech + */ +use crate::models; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::{serde_as, DefaultOnNull}; + +#[serde_as] +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct GenerateOrganizationUsageTimeSeriesResponse { + /// A URL to the JSON Schema for this object. + #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")] + pub schema: Option, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "series")] + pub series: Vec, +} + +impl GenerateOrganizationUsageTimeSeriesResponse { + pub fn new( + series: Vec, + ) -> GenerateOrganizationUsageTimeSeriesResponse { + GenerateOrganizationUsageTimeSeriesResponse { + schema: None, + series, + } + } +} diff --git a/crates/tower-api/src/models/generate_run_statistics_response.rs b/crates/tower-api/src/models/generate_run_statistics_response.rs index e18b3ebb..70bc530f 100644 --- a/crates/tower-api/src/models/generate_run_statistics_response.rs +++ b/crates/tower-api/src/models/generate_run_statistics_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/generate_runner_credentials_response.rs b/crates/tower-api/src/models/generate_runner_credentials_response.rs index aca2d164..0cf2c196 100644 --- a/crates/tower-api/src/models/generate_runner_credentials_response.rs +++ b/crates/tower-api/src/models/generate_runner_credentials_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/get_feature_flag_response_body.rs b/crates/tower-api/src/models/get_feature_flag_response_body.rs index 0ca2be66..cfe6bb45 100644 --- a/crates/tower-api/src/models/get_feature_flag_response_body.rs +++ b/crates/tower-api/src/models/get_feature_flag_response_body.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/guest.rs b/crates/tower-api/src/models/guest.rs index ea2930cd..1d4490cc 100644 --- a/crates/tower-api/src/models/guest.rs +++ b/crates/tower-api/src/models/guest.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/invite_team_member_params.rs b/crates/tower-api/src/models/invite_team_member_params.rs index f730c147..ecf9d14b 100644 --- a/crates/tower-api/src/models/invite_team_member_params.rs +++ b/crates/tower-api/src/models/invite_team_member_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/invite_team_member_response.rs b/crates/tower-api/src/models/invite_team_member_response.rs index 8011f368..0d8acffb 100644 --- a/crates/tower-api/src/models/invite_team_member_response.rs +++ b/crates/tower-api/src/models/invite_team_member_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/leave_team_response.rs b/crates/tower-api/src/models/leave_team_response.rs index 095887bc..ec53a0b7 100644 --- a/crates/tower-api/src/models/leave_team_response.rs +++ b/crates/tower-api/src/models/leave_team_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_alerts_response.rs b/crates/tower-api/src/models/list_alerts_response.rs index 498bf635..1c076702 100644 --- a/crates/tower-api/src/models/list_alerts_response.rs +++ b/crates/tower-api/src/models/list_alerts_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_api_keys_response.rs b/crates/tower-api/src/models/list_api_keys_response.rs index 1fe51b8f..43d8ac38 100644 --- a/crates/tower-api/src/models/list_api_keys_response.rs +++ b/crates/tower-api/src/models/list_api_keys_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_app_environments_response.rs b/crates/tower-api/src/models/list_app_environments_response.rs index e2f1c979..76a2c759 100644 --- a/crates/tower-api/src/models/list_app_environments_response.rs +++ b/crates/tower-api/src/models/list_app_environments_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_app_versions_response.rs b/crates/tower-api/src/models/list_app_versions_response.rs index 926cb45d..730443b3 100644 --- a/crates/tower-api/src/models/list_app_versions_response.rs +++ b/crates/tower-api/src/models/list_app_versions_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_apps_response.rs b/crates/tower-api/src/models/list_apps_response.rs index 216ed560..58d49b1d 100644 --- a/crates/tower-api/src/models/list_apps_response.rs +++ b/crates/tower-api/src/models/list_apps_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_catalogs_response.rs b/crates/tower-api/src/models/list_catalogs_response.rs index 829e14fd..c5db3834 100644 --- a/crates/tower-api/src/models/list_catalogs_response.rs +++ b/crates/tower-api/src/models/list_catalogs_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_environments_response.rs b/crates/tower-api/src/models/list_environments_response.rs index 4d7e7ea5..de3b3700 100644 --- a/crates/tower-api/src/models/list_environments_response.rs +++ b/crates/tower-api/src/models/list_environments_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_guests_response.rs b/crates/tower-api/src/models/list_guests_response.rs index 9dec442d..d8c366c8 100644 --- a/crates/tower-api/src/models/list_guests_response.rs +++ b/crates/tower-api/src/models/list_guests_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_my_team_invitations_response.rs b/crates/tower-api/src/models/list_my_team_invitations_response.rs index 53a270c3..9c87365f 100644 --- a/crates/tower-api/src/models/list_my_team_invitations_response.rs +++ b/crates/tower-api/src/models/list_my_team_invitations_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_runners_response.rs b/crates/tower-api/src/models/list_runners_response.rs index 745674bd..edcea666 100644 --- a/crates/tower-api/src/models/list_runners_response.rs +++ b/crates/tower-api/src/models/list_runners_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_runs_response.rs b/crates/tower-api/src/models/list_runs_response.rs index 6f819a1a..3d622433 100644 --- a/crates/tower-api/src/models/list_runs_response.rs +++ b/crates/tower-api/src/models/list_runs_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_schedules_response.rs b/crates/tower-api/src/models/list_schedules_response.rs index 209b42ed..7eaa5f94 100644 --- a/crates/tower-api/src/models/list_schedules_response.rs +++ b/crates/tower-api/src/models/list_schedules_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_secret_environments_response.rs b/crates/tower-api/src/models/list_secret_environments_response.rs index fdb1d4d1..1c4a0297 100644 --- a/crates/tower-api/src/models/list_secret_environments_response.rs +++ b/crates/tower-api/src/models/list_secret_environments_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_secrets_response.rs b/crates/tower-api/src/models/list_secrets_response.rs index 3292d62c..623502ac 100644 --- a/crates/tower-api/src/models/list_secrets_response.rs +++ b/crates/tower-api/src/models/list_secrets_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_team_invitations_response.rs b/crates/tower-api/src/models/list_team_invitations_response.rs index 8ecb25c4..5b138a92 100644 --- a/crates/tower-api/src/models/list_team_invitations_response.rs +++ b/crates/tower-api/src/models/list_team_invitations_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_team_members_response.rs b/crates/tower-api/src/models/list_team_members_response.rs index da6d3ba9..8564b6c5 100644 --- a/crates/tower-api/src/models/list_team_members_response.rs +++ b/crates/tower-api/src/models/list_team_members_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_teams_response.rs b/crates/tower-api/src/models/list_teams_response.rs index 55c3122e..8fea8f2f 100644 --- a/crates/tower-api/src/models/list_teams_response.rs +++ b/crates/tower-api/src/models/list_teams_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/list_webhooks_response.rs b/crates/tower-api/src/models/list_webhooks_response.rs index abead618..ce232d2b 100644 --- a/crates/tower-api/src/models/list_webhooks_response.rs +++ b/crates/tower-api/src/models/list_webhooks_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/mod.rs b/crates/tower-api/src/models/mod.rs index 400fb7cb..5a3a8045 100644 --- a/crates/tower-api/src/models/mod.rs +++ b/crates/tower-api/src/models/mod.rs @@ -46,10 +46,6 @@ pub mod create_app_params; pub use self::create_app_params::CreateAppParams; pub mod create_app_response; pub use self::create_app_response::CreateAppResponse; -pub mod create_authenticator_params; -pub use self::create_authenticator_params::CreateAuthenticatorParams; -pub mod create_authenticator_response; -pub use self::create_authenticator_response::CreateAuthenticatorResponse; pub mod create_catalog_params; pub use self::create_catalog_params::CreateCatalogParams; pub mod create_catalog_response; @@ -64,10 +60,6 @@ pub mod create_guest_params; pub use self::create_guest_params::CreateGuestParams; pub mod create_guest_response; pub use self::create_guest_response::CreateGuestResponse; -pub mod create_password_reset_params; -pub use self::create_password_reset_params::CreatePasswordResetParams; -pub mod create_password_reset_response; -pub use self::create_password_reset_response::CreatePasswordResetResponse; pub mod create_sandbox_secrets_params; pub use self::create_sandbox_secrets_params::CreateSandboxSecretsParams; pub mod create_sandbox_secrets_response; @@ -98,10 +90,6 @@ pub mod delete_api_key_response; pub use self::delete_api_key_response::DeleteApiKeyResponse; pub mod delete_app_response; pub use self::delete_app_response::DeleteAppResponse; -pub mod delete_authenticator_params; -pub use self::delete_authenticator_params::DeleteAuthenticatorParams; -pub mod delete_authenticator_response; -pub use self::delete_authenticator_response::DeleteAuthenticatorResponse; pub mod delete_catalog_response; pub use self::delete_catalog_response::DeleteCatalogResponse; pub mod delete_guest_output_body; @@ -202,8 +190,8 @@ pub mod featurebase_identity; pub use self::featurebase_identity::FeaturebaseIdentity; pub mod generate_app_statistics_response; pub use self::generate_app_statistics_response::GenerateAppStatisticsResponse; -pub mod generate_authenticator_response; -pub use self::generate_authenticator_response::GenerateAuthenticatorResponse; +pub mod generate_organization_usage_time_series_response; +pub use self::generate_organization_usage_time_series_response::GenerateOrganizationUsageTimeSeriesResponse; pub mod generate_run_statistics_response; pub use self::generate_run_statistics_response::GenerateRunStatisticsResponse; pub mod generate_runner_credentials_response; @@ -228,8 +216,6 @@ pub mod list_app_versions_response; pub use self::list_app_versions_response::ListAppVersionsResponse; pub mod list_apps_response; pub use self::list_apps_response::ListAppsResponse; -pub mod list_authenticators_response; -pub use self::list_authenticators_response::ListAuthenticatorsResponse; pub mod list_catalogs_response; pub use self::list_catalogs_response::ListCatalogsResponse; pub mod list_environments_response; @@ -352,12 +338,14 @@ pub mod test_webhook_response; pub use self::test_webhook_response::TestWebhookResponse; pub mod token; pub use self::token::Token; -pub mod unverified_authenticator; -pub use self::unverified_authenticator::UnverifiedAuthenticator; pub mod update_account_params; pub use self::update_account_params::UpdateAccountParams; pub mod update_account_response; pub use self::update_account_response::UpdateAccountResponse; +pub mod update_app_environment_params; +pub use self::update_app_environment_params::UpdateAppEnvironmentParams; +pub mod update_app_environment_response; +pub use self::update_app_environment_response::UpdateAppEnvironmentResponse; pub mod update_app_params; pub use self::update_app_params::UpdateAppParams; pub mod update_app_response; @@ -380,10 +368,6 @@ pub mod update_organization_params; pub use self::update_organization_params::UpdateOrganizationParams; pub mod update_organization_response; pub use self::update_organization_response::UpdateOrganizationResponse; -pub mod update_password_reset_params; -pub use self::update_password_reset_params::UpdatePasswordResetParams; -pub mod update_password_reset_response; -pub use self::update_password_reset_response::UpdatePasswordResetResponse; pub mod update_plan_params; pub use self::update_plan_params::UpdatePlanParams; pub mod update_plan_response; @@ -414,13 +398,9 @@ pub mod update_webhook_response; pub use self::update_webhook_response::UpdateWebhookResponse; pub mod usage_limit; pub use self::usage_limit::UsageLimit; +pub mod usage_metric_time_series_point; +pub use self::usage_metric_time_series_point::UsageMetricTimeSeriesPoint; pub mod user; pub use self::user::User; -pub mod verified_authenticator; -pub use self::verified_authenticator::VerifiedAuthenticator; -pub mod verify_email_params; -pub use self::verify_email_params::VerifyEmailParams; -pub mod verify_email_response; -pub use self::verify_email_response::VerifyEmailResponse; pub mod webhook; pub use self::webhook::Webhook; diff --git a/crates/tower-api/src/models/organization.rs b/crates/tower-api/src/models/organization.rs index 9ca50392..43aad387 100644 --- a/crates/tower-api/src/models/organization.rs +++ b/crates/tower-api/src/models/organization.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/organization_usage.rs b/crates/tower-api/src/models/organization_usage.rs index a78cc92e..26ee42fb 100644 --- a/crates/tower-api/src/models/organization_usage.rs +++ b/crates/tower-api/src/models/organization_usage.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/pagination.rs b/crates/tower-api/src/models/pagination.rs index d94c1eab..94a36b98 100644 --- a/crates/tower-api/src/models/pagination.rs +++ b/crates/tower-api/src/models/pagination.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/parameter.rs b/crates/tower-api/src/models/parameter.rs index 39ea4fbd..811bd79f 100644 --- a/crates/tower-api/src/models/parameter.rs +++ b/crates/tower-api/src/models/parameter.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/plan.rs b/crates/tower-api/src/models/plan.rs index 6b640e6d..f830dd76 100644 --- a/crates/tower-api/src/models/plan.rs +++ b/crates/tower-api/src/models/plan.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/refresh_session_params.rs b/crates/tower-api/src/models/refresh_session_params.rs index 0350f6e9..37f9619c 100644 --- a/crates/tower-api/src/models/refresh_session_params.rs +++ b/crates/tower-api/src/models/refresh_session_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/refresh_session_response.rs b/crates/tower-api/src/models/refresh_session_response.rs index ba3b045a..f8f2d7c4 100644 --- a/crates/tower-api/src/models/refresh_session_response.rs +++ b/crates/tower-api/src/models/refresh_session_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/regenerate_guest_login_url_params.rs b/crates/tower-api/src/models/regenerate_guest_login_url_params.rs index 25bf9376..8030a2ff 100644 --- a/crates/tower-api/src/models/regenerate_guest_login_url_params.rs +++ b/crates/tower-api/src/models/regenerate_guest_login_url_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/regenerate_guest_login_url_response.rs b/crates/tower-api/src/models/regenerate_guest_login_url_response.rs index 07778e18..130e4623 100644 --- a/crates/tower-api/src/models/regenerate_guest_login_url_response.rs +++ b/crates/tower-api/src/models/regenerate_guest_login_url_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/remove_team_member_params.rs b/crates/tower-api/src/models/remove_team_member_params.rs index 6a40c0d9..ba59de99 100644 --- a/crates/tower-api/src/models/remove_team_member_params.rs +++ b/crates/tower-api/src/models/remove_team_member_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/remove_team_member_response.rs b/crates/tower-api/src/models/remove_team_member_response.rs index 5a21575c..da320640 100644 --- a/crates/tower-api/src/models/remove_team_member_response.rs +++ b/crates/tower-api/src/models/remove_team_member_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/resend_team_invitation_params.rs b/crates/tower-api/src/models/resend_team_invitation_params.rs index 21862271..cbbcbf51 100644 --- a/crates/tower-api/src/models/resend_team_invitation_params.rs +++ b/crates/tower-api/src/models/resend_team_invitation_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/resend_team_invitation_response.rs b/crates/tower-api/src/models/resend_team_invitation_response.rs index aae602ff..90181711 100644 --- a/crates/tower-api/src/models/resend_team_invitation_response.rs +++ b/crates/tower-api/src/models/resend_team_invitation_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run.rs b/crates/tower-api/src/models/run.rs index 90011c99..4e84df41 100644 --- a/crates/tower-api/src/models/run.rs +++ b/crates/tower-api/src/models/run.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -74,8 +74,12 @@ pub struct Run { #[serde_as(as = "DefaultOnNull")] #[serde(rename = "scheduled_at")] pub scheduled_at: String, + /// When the run started executing your code. #[serde(rename = "started_at", deserialize_with = "Option::deserialize")] pub started_at: Option, + /// When the runner environment started to get setup. + #[serde(rename = "starting_at", deserialize_with = "Option::deserialize")] + pub starting_at: Option, #[serde_as(as = "DefaultOnNull")] #[serde(rename = "status")] pub status: Status, @@ -110,6 +114,7 @@ impl Run { run_id: String, scheduled_at: String, started_at: Option, + starting_at: Option, status: Status, status_group: StatusGroup, ) -> Run { @@ -134,6 +139,7 @@ impl Run { run_id, scheduled_at, started_at, + starting_at, status, status_group, subdomain: None, @@ -149,6 +155,8 @@ pub enum Status { Retrying, #[serde(rename = "pending")] Pending, + #[serde(rename = "starting")] + Starting, #[serde(rename = "running")] Running, #[serde(rename = "crashed")] @@ -177,6 +185,7 @@ impl<'de> Deserialize<'de> for Status { "scheduled" => Ok(Self::Scheduled), "retrying" => Ok(Self::Retrying), "pending" => Ok(Self::Pending), + "starting" => Ok(Self::Starting), "running" => Ok(Self::Running), "crashed" => Ok(Self::Crashed), "errored" => Ok(Self::Errored), @@ -188,6 +197,7 @@ impl<'de> Deserialize<'de> for Status { "scheduled", "retrying", "pending", + "starting", "running", "crashed", "errored", diff --git a/crates/tower-api/src/models/run_app_initiator_data.rs b/crates/tower-api/src/models/run_app_initiator_data.rs index 5f6a080c..6c8556b3 100644 --- a/crates/tower-api/src/models/run_app_initiator_data.rs +++ b/crates/tower-api/src/models/run_app_initiator_data.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_app_params.rs b/crates/tower-api/src/models/run_app_params.rs index a630423e..741ed3cd 100644 --- a/crates/tower-api/src/models/run_app_params.rs +++ b/crates/tower-api/src/models/run_app_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_app_response.rs b/crates/tower-api/src/models/run_app_response.rs index 480407ca..abf80054 100644 --- a/crates/tower-api/src/models/run_app_response.rs +++ b/crates/tower-api/src/models/run_app_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_attempt.rs b/crates/tower-api/src/models/run_attempt.rs index 15ca45ac..85b59d80 100644 --- a/crates/tower-api/src/models/run_attempt.rs +++ b/crates/tower-api/src/models/run_attempt.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -24,9 +24,12 @@ pub struct RunAttempt { #[serde_as(as = "DefaultOnNull")] #[serde(rename = "seq")] pub seq: i64, - /// When this attempt started. + /// When the run started executing your code. #[serde(rename = "started_at", deserialize_with = "Option::deserialize")] pub started_at: Option, + /// When the runner environment started to get setup. + #[serde(rename = "starting_at", deserialize_with = "Option::deserialize")] + pub starting_at: Option, /// Terminal status of this attempt. #[serde_as(as = "DefaultOnNull")] #[serde(rename = "status")] @@ -39,6 +42,7 @@ impl RunAttempt { exit_code: Option, seq: i64, started_at: Option, + starting_at: Option, status: String, ) -> RunAttempt { RunAttempt { @@ -46,6 +50,7 @@ impl RunAttempt { exit_code, seq, started_at, + starting_at, status, } } diff --git a/crates/tower-api/src/models/run_failure_alert.rs b/crates/tower-api/src/models/run_failure_alert.rs index 0f30f2d3..93ce4473 100644 --- a/crates/tower-api/src/models/run_failure_alert.rs +++ b/crates/tower-api/src/models/run_failure_alert.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_graph_node.rs b/crates/tower-api/src/models/run_graph_node.rs index d0eb6652..316a3882 100644 --- a/crates/tower-api/src/models/run_graph_node.rs +++ b/crates/tower-api/src/models/run_graph_node.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_graph_run_id.rs b/crates/tower-api/src/models/run_graph_run_id.rs index b5f3937f..fc7047d9 100644 --- a/crates/tower-api/src/models/run_graph_run_id.rs +++ b/crates/tower-api/src/models/run_graph_run_id.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_initiator.rs b/crates/tower-api/src/models/run_initiator.rs index fac88e3b..00cbf42f 100644 --- a/crates/tower-api/src/models/run_initiator.rs +++ b/crates/tower-api/src/models/run_initiator.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_initiator_details.rs b/crates/tower-api/src/models/run_initiator_details.rs index 4c21e555..cc6ff315 100644 --- a/crates/tower-api/src/models/run_initiator_details.rs +++ b/crates/tower-api/src/models/run_initiator_details.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_log_line.rs b/crates/tower-api/src/models/run_log_line.rs index b10efadc..1dcad0c9 100644 --- a/crates/tower-api/src/models/run_log_line.rs +++ b/crates/tower-api/src/models/run_log_line.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_parameter.rs b/crates/tower-api/src/models/run_parameter.rs index 4f3fb67b..cb98bfcd 100644 --- a/crates/tower-api/src/models/run_parameter.rs +++ b/crates/tower-api/src/models/run_parameter.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -17,6 +17,14 @@ pub struct RunParameter { /// Whether this parameter is hidden/secret. Defaults to false. #[serde(rename = "hidden", skip_serializing_if = "Option::is_none")] pub hidden: Option, + /// Whether this parameter's value was supplied as an override at run/schedule creation time (true) or comes from the app version's default (false). + #[serde( + rename = "is_override", + default, + with = "::serde_with::rust::double_option", + skip_serializing_if = "Option::is_none" + )] + pub is_override: Option>, #[serde_as(as = "DefaultOnNull")] #[serde(rename = "name")] pub name: String, @@ -29,6 +37,7 @@ impl RunParameter { pub fn new(name: String, value: String) -> RunParameter { RunParameter { hidden: None, + is_override: None, name, value, } diff --git a/crates/tower-api/src/models/run_parameter_input.rs b/crates/tower-api/src/models/run_parameter_input.rs new file mode 100644 index 00000000..08ffe6dd --- /dev/null +++ b/crates/tower-api/src/models/run_parameter_input.rs @@ -0,0 +1,36 @@ +/* + * Tower API + * + * REST API to interact with Tower Services. + * + * The version of the OpenAPI document: 0.10.23-preview + * Contact: hello@tower.dev + * Generated by: https://openapi-generator.tech + */ +use crate::models; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::{serde_as, DefaultOnNull}; + +#[serde_as] +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct RunParameterInput { + /// Whether this parameter is hidden/secret. Defaults to false. + #[serde(rename = "hidden", skip_serializing_if = "Option::is_none")] + pub hidden: Option, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "name")] + pub name: String, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "value")] + pub value: String, +} + +impl RunParameterInput { + pub fn new(name: String, value: String) -> RunParameterInput { + RunParameterInput { + hidden: None, + name, + value, + } + } +} diff --git a/crates/tower-api/src/models/run_results.rs b/crates/tower-api/src/models/run_results.rs index 538fcba3..72d6c3e7 100644 --- a/crates/tower-api/src/models/run_results.rs +++ b/crates/tower-api/src/models/run_results.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -35,6 +35,9 @@ pub struct RunResults { #[serde_as(as = "DefaultOnNull")] #[serde(rename = "running")] pub running: i64, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "starting")] + pub starting: i64, } impl RunResults { @@ -46,6 +49,7 @@ impl RunResults { pending: i64, retrying: i64, running: i64, + starting: i64, ) -> RunResults { RunResults { cancelled, @@ -55,6 +59,7 @@ impl RunResults { pending, retrying, running, + starting, } } } diff --git a/crates/tower-api/src/models/run_retry_policy.rs b/crates/tower-api/src/models/run_retry_policy.rs index 7484ef72..bfe9489d 100644 --- a/crates/tower-api/src/models/run_retry_policy.rs +++ b/crates/tower-api/src/models/run_retry_policy.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_run_initiator_details.rs b/crates/tower-api/src/models/run_run_initiator_details.rs index 2f1b3eb4..4015ed98 100644 --- a/crates/tower-api/src/models/run_run_initiator_details.rs +++ b/crates/tower-api/src/models/run_run_initiator_details.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_statistics.rs b/crates/tower-api/src/models/run_statistics.rs index 86744b58..af3a61f8 100644 --- a/crates/tower-api/src/models/run_statistics.rs +++ b/crates/tower-api/src/models/run_statistics.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/run_timeseries_point.rs b/crates/tower-api/src/models/run_timeseries_point.rs index a4021b24..23bd370d 100644 --- a/crates/tower-api/src/models/run_timeseries_point.rs +++ b/crates/tower-api/src/models/run_timeseries_point.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -42,6 +42,9 @@ pub struct RunTimeseriesPoint { #[serde_as(as = "DefaultOnNull")] #[serde(rename = "scheduled")] pub scheduled: i64, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "starting")] + pub starting: i64, } impl RunTimeseriesPoint { @@ -55,6 +58,7 @@ impl RunTimeseriesPoint { retrying: i64, running: i64, scheduled: i64, + starting: i64, ) -> RunTimeseriesPoint { RunTimeseriesPoint { cancelled, @@ -66,6 +70,7 @@ impl RunTimeseriesPoint { retrying, running, scheduled, + starting, } } } diff --git a/crates/tower-api/src/models/runner.rs b/crates/tower-api/src/models/runner.rs index 50e4c806..3835beeb 100644 --- a/crates/tower-api/src/models/runner.rs +++ b/crates/tower-api/src/models/runner.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/runner_credentials.rs b/crates/tower-api/src/models/runner_credentials.rs index 9833f13f..1fd53e86 100644 --- a/crates/tower-api/src/models/runner_credentials.rs +++ b/crates/tower-api/src/models/runner_credentials.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/schedule.rs b/crates/tower-api/src/models/schedule.rs index a8dde710..fde474d2 100644 --- a/crates/tower-api/src/models/schedule.rs +++ b/crates/tower-api/src/models/schedule.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -22,7 +22,7 @@ pub struct Schedule { #[serde_as(as = "DefaultOnNull")] #[serde(rename = "app_status")] pub app_status: AppStatus, - /// The specific app version to run, or null for the default version + /// This property is deprecated. Schedules inherit the version from their environment. This field returns the environment's current version. #[serde(rename = "app_version", skip_serializing_if = "Option::is_none")] pub app_version: Option, /// The timestamp when the schedule was created diff --git a/crates/tower-api/src/models/schedule_run_initiator_details.rs b/crates/tower-api/src/models/schedule_run_initiator_details.rs index 78e15549..ae103d42 100644 --- a/crates/tower-api/src/models/schedule_run_initiator_details.rs +++ b/crates/tower-api/src/models/schedule_run_initiator_details.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/search_runs_response.rs b/crates/tower-api/src/models/search_runs_response.rs index bda0b32c..9971ebaf 100644 --- a/crates/tower-api/src/models/search_runs_response.rs +++ b/crates/tower-api/src/models/search_runs_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/secret.rs b/crates/tower-api/src/models/secret.rs index 29e9025e..fdbc37b9 100644 --- a/crates/tower-api/src/models/secret.rs +++ b/crates/tower-api/src/models/secret.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/server_sent_events_inner.rs b/crates/tower-api/src/models/server_sent_events_inner.rs index 37f57f13..777b2918 100644 --- a/crates/tower-api/src/models/server_sent_events_inner.rs +++ b/crates/tower-api/src/models/server_sent_events_inner.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/server_sent_events_inner_1.rs b/crates/tower-api/src/models/server_sent_events_inner_1.rs index 5e671541..4374a4c9 100644 --- a/crates/tower-api/src/models/server_sent_events_inner_1.rs +++ b/crates/tower-api/src/models/server_sent_events_inner_1.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/server_sent_events_inner_2.rs b/crates/tower-api/src/models/server_sent_events_inner_2.rs index 98911abe..aa3416da 100644 --- a/crates/tower-api/src/models/server_sent_events_inner_2.rs +++ b/crates/tower-api/src/models/server_sent_events_inner_2.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/session.rs b/crates/tower-api/src/models/session.rs index 0cba667a..63873a02 100644 --- a/crates/tower-api/src/models/session.rs +++ b/crates/tower-api/src/models/session.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -14,6 +14,7 @@ use serde_with::{serde_as, DefaultOnNull}; #[serde_as] #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct Session { + /// This property is deprecated. It will be removed in a future version. #[serde_as(as = "DefaultOnNull")] #[serde(rename = "featurebase_identity")] pub featurebase_identity: models::FeaturebaseIdentity, diff --git a/crates/tower-api/src/models/shoulder_tap.rs b/crates/tower-api/src/models/shoulder_tap.rs index dec17e33..3d5b91f7 100644 --- a/crates/tower-api/src/models/shoulder_tap.rs +++ b/crates/tower-api/src/models/shoulder_tap.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/sse_warning.rs b/crates/tower-api/src/models/sse_warning.rs index 78b4f748..28dc3f9e 100644 --- a/crates/tower-api/src/models/sse_warning.rs +++ b/crates/tower-api/src/models/sse_warning.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/statistics_settings.rs b/crates/tower-api/src/models/statistics_settings.rs index 6ab7bb5e..8026f7dc 100644 --- a/crates/tower-api/src/models/statistics_settings.rs +++ b/crates/tower-api/src/models/statistics_settings.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/team.rs b/crates/tower-api/src/models/team.rs index 08da5e37..537b57a1 100644 --- a/crates/tower-api/src/models/team.rs +++ b/crates/tower-api/src/models/team.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/team_invitation.rs b/crates/tower-api/src/models/team_invitation.rs index f7aeeff6..1a649f7b 100644 --- a/crates/tower-api/src/models/team_invitation.rs +++ b/crates/tower-api/src/models/team_invitation.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/team_membership.rs b/crates/tower-api/src/models/team_membership.rs index 0d19d661..ab61bc59 100644 --- a/crates/tower-api/src/models/team_membership.rs +++ b/crates/tower-api/src/models/team_membership.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/test_webhook_response.rs b/crates/tower-api/src/models/test_webhook_response.rs index 186b1e56..edb69308 100644 --- a/crates/tower-api/src/models/test_webhook_response.rs +++ b/crates/tower-api/src/models/test_webhook_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/token.rs b/crates/tower-api/src/models/token.rs index e0ec1806..bd119e00 100644 --- a/crates/tower-api/src/models/token.rs +++ b/crates/tower-api/src/models/token.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_account_params.rs b/crates/tower-api/src/models/update_account_params.rs index 7190e849..7f051a0b 100644 --- a/crates/tower-api/src/models/update_account_params.rs +++ b/crates/tower-api/src/models/update_account_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_account_response.rs b/crates/tower-api/src/models/update_account_response.rs index 09653197..6b289c94 100644 --- a/crates/tower-api/src/models/update_account_response.rs +++ b/crates/tower-api/src/models/update_account_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_app_environment_params.rs b/crates/tower-api/src/models/update_app_environment_params.rs new file mode 100644 index 00000000..d0fbc7f2 --- /dev/null +++ b/crates/tower-api/src/models/update_app_environment_params.rs @@ -0,0 +1,33 @@ +/* + * Tower API + * + * REST API to interact with Tower Services. + * + * The version of the OpenAPI document: v0.10.24 + * Contact: hello@tower.dev + * Generated by: https://openapi-generator.tech + */ +use crate::models; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::{serde_as, DefaultOnNull}; + +#[serde_as] +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct UpdateAppEnvironmentParams { + /// A URL to the JSON Schema for this object. + #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")] + pub schema: Option, + /// The version to deploy to this environment, e.g. 'v1', 'v2'. + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "version")] + pub version: String, +} + +impl UpdateAppEnvironmentParams { + pub fn new(version: String) -> UpdateAppEnvironmentParams { + UpdateAppEnvironmentParams { + schema: None, + version, + } + } +} diff --git a/crates/tower-api/src/models/update_app_environment_response.rs b/crates/tower-api/src/models/update_app_environment_response.rs new file mode 100644 index 00000000..0da5a43b --- /dev/null +++ b/crates/tower-api/src/models/update_app_environment_response.rs @@ -0,0 +1,36 @@ +/* + * Tower API + * + * REST API to interact with Tower Services. + * + * The version of the OpenAPI document: v0.10.24 + * Contact: hello@tower.dev + * Generated by: https://openapi-generator.tech + */ +use crate::models; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::{serde_as, DefaultOnNull}; + +#[serde_as] +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct UpdateAppEnvironmentResponse { + /// A URL to the JSON Schema for this object. + #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")] + pub schema: Option, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "environment")] + pub environment: String, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "version")] + pub version: String, +} + +impl UpdateAppEnvironmentResponse { + pub fn new(environment: String, version: String) -> UpdateAppEnvironmentResponse { + UpdateAppEnvironmentResponse { + schema: None, + environment, + version, + } + } +} diff --git a/crates/tower-api/src/models/update_app_params.rs b/crates/tower-api/src/models/update_app_params.rs index 72b44704..7b030fa8 100644 --- a/crates/tower-api/src/models/update_app_params.rs +++ b/crates/tower-api/src/models/update_app_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_app_response.rs b/crates/tower-api/src/models/update_app_response.rs index 6aa3fdfa..1b6e34a0 100644 --- a/crates/tower-api/src/models/update_app_response.rs +++ b/crates/tower-api/src/models/update_app_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_catalog_params.rs b/crates/tower-api/src/models/update_catalog_params.rs index 6732636f..8546d7be 100644 --- a/crates/tower-api/src/models/update_catalog_params.rs +++ b/crates/tower-api/src/models/update_catalog_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_catalog_response.rs b/crates/tower-api/src/models/update_catalog_response.rs index b2db4456..f95ad2df 100644 --- a/crates/tower-api/src/models/update_catalog_response.rs +++ b/crates/tower-api/src/models/update_catalog_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_email_preferences_body.rs b/crates/tower-api/src/models/update_email_preferences_body.rs index 5c0f1e0b..03e86fbf 100644 --- a/crates/tower-api/src/models/update_email_preferences_body.rs +++ b/crates/tower-api/src/models/update_email_preferences_body.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_environment_params.rs b/crates/tower-api/src/models/update_environment_params.rs index 9be932eb..750e217b 100644 --- a/crates/tower-api/src/models/update_environment_params.rs +++ b/crates/tower-api/src/models/update_environment_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_environment_response.rs b/crates/tower-api/src/models/update_environment_response.rs index e7a74643..0d94e746 100644 --- a/crates/tower-api/src/models/update_environment_response.rs +++ b/crates/tower-api/src/models/update_environment_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_my_team_invitation_params.rs b/crates/tower-api/src/models/update_my_team_invitation_params.rs index 5c17075e..388fce68 100644 --- a/crates/tower-api/src/models/update_my_team_invitation_params.rs +++ b/crates/tower-api/src/models/update_my_team_invitation_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_my_team_invitation_response.rs b/crates/tower-api/src/models/update_my_team_invitation_response.rs index 8f077b5a..bcbf9136 100644 --- a/crates/tower-api/src/models/update_my_team_invitation_response.rs +++ b/crates/tower-api/src/models/update_my_team_invitation_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_organization_params.rs b/crates/tower-api/src/models/update_organization_params.rs index cf153c0d..2912b546 100644 --- a/crates/tower-api/src/models/update_organization_params.rs +++ b/crates/tower-api/src/models/update_organization_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_organization_response.rs b/crates/tower-api/src/models/update_organization_response.rs index b485de14..782b6124 100644 --- a/crates/tower-api/src/models/update_organization_response.rs +++ b/crates/tower-api/src/models/update_organization_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_plan_params.rs b/crates/tower-api/src/models/update_plan_params.rs index 283ce407..6252fb2a 100644 --- a/crates/tower-api/src/models/update_plan_params.rs +++ b/crates/tower-api/src/models/update_plan_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_plan_response.rs b/crates/tower-api/src/models/update_plan_response.rs index 9cdfcd1b..c1bb2d58 100644 --- a/crates/tower-api/src/models/update_plan_response.rs +++ b/crates/tower-api/src/models/update_plan_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_schedule_params.rs b/crates/tower-api/src/models/update_schedule_params.rs index 44a0e210..ba2541c8 100644 --- a/crates/tower-api/src/models/update_schedule_params.rs +++ b/crates/tower-api/src/models/update_schedule_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ @@ -17,7 +17,7 @@ pub struct UpdateScheduleParams { /// A URL to the JSON Schema for this object. #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")] pub schema: Option, - /// The specific app version to run (if omitted, will use the app's default version) + /// This property is deprecated and ignored. Schedules inherit the version from their environment. #[serde( rename = "app_version", default, diff --git a/crates/tower-api/src/models/update_schedule_response.rs b/crates/tower-api/src/models/update_schedule_response.rs index 91949516..a75eeca5 100644 --- a/crates/tower-api/src/models/update_schedule_response.rs +++ b/crates/tower-api/src/models/update_schedule_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_secret_params.rs b/crates/tower-api/src/models/update_secret_params.rs index 40a5affe..b4f02c80 100644 --- a/crates/tower-api/src/models/update_secret_params.rs +++ b/crates/tower-api/src/models/update_secret_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_secret_response.rs b/crates/tower-api/src/models/update_secret_response.rs index 33cc1518..589c5013 100644 --- a/crates/tower-api/src/models/update_secret_response.rs +++ b/crates/tower-api/src/models/update_secret_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_team_member_params.rs b/crates/tower-api/src/models/update_team_member_params.rs index 8886b6e2..5b34f5d7 100644 --- a/crates/tower-api/src/models/update_team_member_params.rs +++ b/crates/tower-api/src/models/update_team_member_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_team_member_response.rs b/crates/tower-api/src/models/update_team_member_response.rs index 8c530240..42511c70 100644 --- a/crates/tower-api/src/models/update_team_member_response.rs +++ b/crates/tower-api/src/models/update_team_member_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_team_params.rs b/crates/tower-api/src/models/update_team_params.rs index a9796866..4dcef519 100644 --- a/crates/tower-api/src/models/update_team_params.rs +++ b/crates/tower-api/src/models/update_team_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_team_response.rs b/crates/tower-api/src/models/update_team_response.rs index 8fa559a9..28c1734c 100644 --- a/crates/tower-api/src/models/update_team_response.rs +++ b/crates/tower-api/src/models/update_team_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_user_params.rs b/crates/tower-api/src/models/update_user_params.rs index 0377d738..a95860ca 100644 --- a/crates/tower-api/src/models/update_user_params.rs +++ b/crates/tower-api/src/models/update_user_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_user_response.rs b/crates/tower-api/src/models/update_user_response.rs index 359bb2c3..727a11d9 100644 --- a/crates/tower-api/src/models/update_user_response.rs +++ b/crates/tower-api/src/models/update_user_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_webhook_params.rs b/crates/tower-api/src/models/update_webhook_params.rs index 79b84cfd..2272a311 100644 --- a/crates/tower-api/src/models/update_webhook_params.rs +++ b/crates/tower-api/src/models/update_webhook_params.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/update_webhook_response.rs b/crates/tower-api/src/models/update_webhook_response.rs index 833f61ca..90ba489a 100644 --- a/crates/tower-api/src/models/update_webhook_response.rs +++ b/crates/tower-api/src/models/update_webhook_response.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/usage_limit.rs b/crates/tower-api/src/models/usage_limit.rs index 985ce95b..53252d37 100644 --- a/crates/tower-api/src/models/usage_limit.rs +++ b/crates/tower-api/src/models/usage_limit.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/usage_metric_time_series_point.rs b/crates/tower-api/src/models/usage_metric_time_series_point.rs new file mode 100644 index 00000000..38d14c80 --- /dev/null +++ b/crates/tower-api/src/models/usage_metric_time_series_point.rs @@ -0,0 +1,57 @@ +/* + * Tower API + * + * REST API to interact with Tower Services. + * + * The version of the OpenAPI document: v0.10.24 + * Contact: hello@tower.dev + * Generated by: https://openapi-generator.tech + */ +use crate::models; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::{serde_as, DefaultOnNull}; + +#[serde_as] +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct UsageMetricTimeSeriesPoint { + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "date")] + pub date: String, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "name")] + pub name: Name, + #[serde_as(as = "DefaultOnNull")] + #[serde(rename = "value")] + pub value: i64, +} + +impl UsageMetricTimeSeriesPoint { + pub fn new(date: String, name: Name, value: i64) -> UsageMetricTimeSeriesPoint { + UsageMetricTimeSeriesPoint { date, name, value } + } +} +/// +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)] +pub enum Name { + #[serde(rename = "run_seconds")] + RunSeconds, +} + +impl Default for Name { + fn default() -> Name { + Self::RunSeconds + } +} + +impl<'de> Deserialize<'de> for Name { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + match s.to_lowercase().as_str() { + "run_seconds" => Ok(Self::RunSeconds), + _ => Err(serde::de::Error::unknown_variant(&s, &["run_seconds"])), + } + } +} diff --git a/crates/tower-api/src/models/user.rs b/crates/tower-api/src/models/user.rs index 7c641aed..d7e31814 100644 --- a/crates/tower-api/src/models/user.rs +++ b/crates/tower-api/src/models/user.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-api/src/models/webhook.rs b/crates/tower-api/src/models/webhook.rs index 6e3aaab6..ad5db127 100644 --- a/crates/tower-api/src/models/webhook.rs +++ b/crates/tower-api/src/models/webhook.rs @@ -3,7 +3,7 @@ * * REST API to interact with Tower Services. * - * The version of the OpenAPI document: v0.10.17 + * The version of the OpenAPI document: v0.10.24 * Contact: hello@tower.dev * Generated by: https://openapi-generator.tech */ diff --git a/crates/tower-cmd/Cargo.toml b/crates/tower-cmd/Cargo.toml index 701bf6e3..cb6a5f4f 100644 --- a/crates/tower-cmd/Cargo.toml +++ b/crates/tower-cmd/Cargo.toml @@ -21,6 +21,7 @@ reqwest = { workspace = true } reqwest-eventsource = { workspace = true } rpassword = { workspace = true } rsa = { workspace = true } +rustls = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } snafu = { workspace = true } diff --git a/crates/tower-cmd/src/api.rs b/crates/tower-cmd/src/api.rs index 0297bf11..07f0dca8 100644 --- a/crates/tower-cmd/src/api.rs +++ b/crates/tower-cmd/src/api.rs @@ -3,10 +3,12 @@ use futures_util::StreamExt; use http::StatusCode; use reqwest_eventsource::{Event, EventSource}; use std::collections::HashMap; +use std::future::Future; use tokio::sync::mpsc; use tower_api::apis::configuration; use tower_api::apis::Error; use tower_api::apis::ResponseContent; +use tower_api::models::Pagination; use tower_api::models::RunParameter; use tower_telemetry::debug; @@ -19,9 +21,100 @@ pub trait ResponseEntity { fn extract_data(self) -> Option; } +/// Trait for API responses that contain paginated items. +trait PaginatedResponse { + type Item; + fn pagination(&self) -> &Pagination; + fn into_items(self) -> Vec; +} + +impl PaginatedResponse for tower_api::models::ListAppsResponse { + type Item = tower_api::models::AppSummary; + fn pagination(&self) -> &Pagination { &self.pages } + fn into_items(self) -> Vec { self.apps } +} + +impl PaginatedResponse for tower_api::models::ListTeamsResponse { + type Item = tower_api::models::Team; + fn pagination(&self) -> &Pagination { &self.pages } + fn into_items(self) -> Vec { self.teams } +} + +impl PaginatedResponse for tower_api::models::ListSecretsResponse { + type Item = tower_api::models::Secret; + fn pagination(&self) -> &Pagination { &self.pages } + fn into_items(self) -> Vec { self.secrets } +} + +impl PaginatedResponse for tower_api::models::ListCatalogsResponse { + type Item = tower_api::models::Catalog; + fn pagination(&self) -> &Pagination { &self.pages } + fn into_items(self) -> Vec { self.catalogs } +} + +impl PaginatedResponse for tower_api::models::ListEnvironmentsResponse { + type Item = tower_api::models::Environment; + fn pagination(&self) -> &Pagination { &self.pages } + fn into_items(self) -> Vec { self.environments } +} + +impl PaginatedResponse for tower_api::models::ListSchedulesResponse { + type Item = tower_api::models::Schedule; + fn pagination(&self) -> &Pagination { &self.pages } + fn into_items(self) -> Vec { self.schedules } +} + +/// Fetches pages from a paginated API endpoint, honoring the caller's +/// page_size / paginate / page / max_items settings on Config. +/// +/// Page numbers follow the API convention: pages are 1-indexed, and `page = 0` +/// (or unset on the server side) means "no pagination, return everything in one +/// response". The loop sends `page = 0` exactly once if the caller did not opt +/// into a starting page, otherwise it iterates 1..=num_pages. +async fn fetch_all_pages(config: &Config, fetch: F) -> Result, Error> +where + R: PaginatedResponse, + F: Fn(i64, i64) -> Fut, + Fut: Future>>, +{ + let page_size = config.page_size(); + let mut all_items = Vec::new(); + let mut page: i64 = config.page.unwrap_or(0); + + loop { + let response = fetch(page, page_size).await?; + let num_pages = response.pagination().num_pages; + all_items.extend(response.into_items()); + + if let Some(max) = config.max_items { + if all_items.len() as i64 >= max { + all_items.truncate(max as usize); + break; + } + } + + // page == 0 means the server returned all items in a single response. + if page == 0 { + break; + } + + if !config.paginate { + break; + } + + page += 1; + if page > num_pages || page > 100 { + break; + } + } + + Ok(all_items) +} + pub async fn describe_app( config: &Config, name: &str, + environment: Option<&str>, ) -> Result< tower_api::models::DescribeAppResponse, Error, @@ -34,6 +127,7 @@ pub async fn describe_app( start_at: None, end_at: None, timezone: None, + environment: environment.map(|s| s.to_string()), }; unwrap_api_response(tower_api::apis::default_api::describe_app( @@ -44,21 +138,29 @@ pub async fn describe_app( pub async fn list_apps( config: &Config, -) -> Result> + environment: Option<&str>, +) -> Result, Error> { - let api_config = &config.into(); - - let params = tower_api::apis::default_api::ListAppsParams { - query: None, - page: None, - page_size: None, - num_runs: Some(0), - sort: None, - filter: None, - environment: None, - }; - - unwrap_api_response(tower_api::apis::default_api::list_apps(api_config, params)).await + let api_config: configuration::Configuration = config.into(); + let environment = environment.map(|s| s.to_string()); + + fetch_all_pages(config, |page, page_size| { + let api_config = &api_config; + let environment = &environment; + async move { + let params = tower_api::apis::default_api::ListAppsParams { + query: None, + page: Some(page), + page_size: Some(page_size), + num_runs: Some(0), + sort: None, + filter: None, + environment: environment.clone(), + }; + unwrap_api_response(tower_api::apis::default_api::list_apps(api_config, params)).await + } + }) + .await } pub async fn create_app( @@ -224,22 +326,27 @@ pub async fn list_catalogs( config: &Config, env: &str, all: bool, -) -> Result< - tower_api::models::ListCatalogsResponse, - Error, -> { - let api_config = &config.into(); - - let params = tower_api::apis::default_api::ListCatalogsParams { - environment: Some(env.to_string()), - all: Some(all), - page: None, - page_size: None, - }; - - unwrap_api_response(tower_api::apis::default_api::list_catalogs( - api_config, params, - )) +) -> Result, Error> +{ + let api_config: configuration::Configuration = config.into(); + let env = env.to_string(); + + fetch_all_pages(config, |page, page_size| { + let api_config = &api_config; + let env = &env; + async move { + let params = tower_api::apis::default_api::ListCatalogsParams { + environment: Some(env.to_string()), + all: Some(all), + page: Some(page), + page_size: Some(page_size), + }; + unwrap_api_response(tower_api::apis::default_api::list_catalogs( + api_config, params, + )) + .await + } + }) .await } @@ -268,22 +375,27 @@ pub async fn list_secrets( config: &Config, env: &str, all: bool, -) -> Result< - tower_api::models::ListSecretsResponse, - Error, -> { - let api_config = &config.into(); - - let params = tower_api::apis::default_api::ListSecretsParams { - environment: Some(env.to_string()), - all: Some(all), - page: None, - page_size: None, - }; - - unwrap_api_response(tower_api::apis::default_api::list_secrets( - api_config, params, - )) +) -> Result, Error> +{ + let api_config: configuration::Configuration = config.into(); + let env = env.to_string(); + + fetch_all_pages(config, |page, page_size| { + let api_config = &api_config; + let env = &env; + async move { + let params = tower_api::apis::default_api::ListSecretsParams { + environment: Some(env.to_string()), + all: Some(all), + page: Some(page), + page_size: Some(page_size), + }; + unwrap_api_response(tower_api::apis::default_api::list_secrets( + api_config, params, + )) + .await + } + }) .await } @@ -404,18 +516,20 @@ pub async fn refresh_session( pub async fn list_teams( config: &Config, -) -> Result< - tower_api::models::ListTeamsResponse, - Error, -> { - let api_config = &config.into(); - - let params = tower_api::apis::default_api::ListTeamsParams { - page: None, - page_size: None, - }; +) -> Result, Error> { + let api_config: configuration::Configuration = config.into(); - unwrap_api_response(tower_api::apis::default_api::list_teams(api_config, params)).await + fetch_all_pages(config, |page, page_size| { + let api_config = &api_config; + async move { + let params = tower_api::apis::default_api::ListTeamsParams { + page: Some(page), + page_size: Some(page_size), + }; + unwrap_api_response(tower_api::apis::default_api::list_teams(api_config, params)).await + } + }) + .await } pub enum LogStreamEvent { @@ -576,6 +690,7 @@ async fn unwrap_api_response(api_call: F) -> Result> where F: std::future::Future, Error>>, T: ResponseEntity, + T::Data: serde::de::DeserializeOwned, { match api_call.await { Ok(response) => { @@ -595,11 +710,28 @@ where if let Some(data) = entity.extract_data() { Ok(data) } else { + let truncated = if response.content.len() > 500 { + format!("{}...(truncated)", &response.content[..500]) + } else { + response.content.clone() + }; + // Try explicit deserialization to get the actual error message + let deser_error = serde_json::from_str::(&response.content) + .err() + .map(|e| format!(" Deserialization error: {}", e)) + .unwrap_or_default(); + debug!( + "Failed to extract data from API response:{} Content: {}", + deser_error, truncated + ); let err = Error::ResponseError( tower_api::apis::ResponseContent { tower_trace_id: "".to_string(), status: StatusCode::NO_CONTENT, - content: "Received a response from the server that the CLI wasn't able to understand".to_string(), + content: format!( + "Received a response from the server that the CLI wasn't able to understand.{} Response: {}", + deser_error, truncated + ), entity: None, }, ); @@ -860,18 +992,24 @@ impl ResponseEntity for tower_api::apis::default_api::ListEnvironmentsSuccess { pub async fn list_environments( config: &Config, ) -> Result< - tower_api::models::ListEnvironmentsResponse, + Vec, Error, > { - let api_config = &config.into(); - let params = tower_api::apis::default_api::ListEnvironmentsParams { - page: Some(0), - page_size: Some(1000), - }; + let api_config: configuration::Configuration = config.into(); - unwrap_api_response(tower_api::apis::default_api::list_environments( - api_config, params, - )) + fetch_all_pages(config, |page, page_size| { + let api_config = &api_config; + async move { + let params = tower_api::apis::default_api::ListEnvironmentsParams { + page: Some(page), + page_size: Some(page_size), + }; + unwrap_api_response(tower_api::apis::default_api::list_environments( + api_config, params, + )) + .await + } + }) .await } @@ -901,21 +1039,26 @@ pub async fn list_schedules( config: &Config, _app_name: Option<&str>, environment: Option<&str>, -) -> Result< - tower_api::models::ListSchedulesResponse, - Error, -> { - let api_config = &config.into(); - - let params = tower_api::apis::default_api::ListSchedulesParams { - environment: environment.map(String::from), - page: None, - page_size: None, - }; - - unwrap_api_response(tower_api::apis::default_api::list_schedules( - api_config, params, - )) +) -> Result, Error> +{ + let api_config: configuration::Configuration = config.into(); + let environment = environment.map(String::from); + + fetch_all_pages(config, |page, page_size| { + let api_config = &api_config; + let environment = &environment; + async move { + let params = tower_api::apis::default_api::ListSchedulesParams { + environment: environment.clone(), + page: Some(page), + page_size: Some(page_size), + }; + unwrap_api_response(tower_api::apis::default_api::list_schedules( + api_config, params, + )) + .await + } + }) .await } @@ -935,6 +1078,7 @@ pub async fn create_schedule( params .into_iter() .map(|(key, value)| RunParameter { + is_override: None, name: key, value, hidden: None, @@ -973,6 +1117,7 @@ pub async fn update_schedule( params .into_iter() .map(|(key, value)| RunParameter { + is_override: None, name: key, value, hidden: None, @@ -1079,10 +1224,8 @@ pub async fn cancel_run( config: &Config, name: &str, seq: i64, -) -> Result< - tower_api::models::CancelRunResponse, - Error, -> { +) -> Result> +{ let api_config = &config.into(); let params = tower_api::apis::default_api::CancelRunParams { @@ -1090,10 +1233,7 @@ pub async fn cancel_run( seq, }; - unwrap_api_response(tower_api::apis::default_api::cancel_run( - api_config, params, - )) - .await + unwrap_api_response(tower_api::apis::default_api::cancel_run(api_config, params)).await } impl ResponseEntity for tower_api::apis::default_api::CancelRunSuccess { diff --git a/crates/tower-cmd/src/apps.rs b/crates/tower-cmd/src/apps.rs index ab632620..e04c3dc9 100644 --- a/crates/tower-cmd/src/apps.rs +++ b/crates/tower-cmd/src/apps.rs @@ -5,13 +5,24 @@ use tokio::time::{sleep, Duration, Instant}; use tower_api::models::{Run, RunLogLine}; -use crate::{api, output}; +use crate::{api, output, util::cmd}; pub fn apps_cmd() -> Command { Command::new("apps") .about("Manage the apps in your current Tower account") .arg_required_else_help(true) - .subcommand(Command::new("list").about("List all apps in your Tower account")) + .subcommand( + Command::new("list") + .arg( + Arg::new("environment") + .short('e') + .long("environment") + .value_parser(value_parser!(String)) + .help("Filter apps by environment") + .action(clap::ArgAction::Set), + ) + .about("List all apps in your Tower account"), + ) .subcommand( Command::new("show") .arg( @@ -21,6 +32,15 @@ pub fn apps_cmd() -> Command { .required(true) .help("Name of the app"), ) + .arg( + Arg::new("environment") + .short('e') + .long("environment") + .default_value("default") + .value_parser(value_parser!(String)) + .help("The environment to resolve the app against") + .action(clap::ArgAction::Set), + ) .about("Show details for a Tower app and its recent runs"), ) .subcommand( @@ -97,9 +117,13 @@ pub fn apps_cmd() -> Command { } pub async fn do_logs(config: Config, cmd: &ArgMatches) { - let app_name_raw = cmd.get_one::("app_name").expect("app_name is required"); + let app_name_raw = cmd + .get_one::("app_name") + .expect("app_name is required"); let (name, seq) = if let Some((name, num_str)) = app_name_raw.split_once('#') { - let num = num_str.parse::().unwrap_or_else(|_| output::die("Run number must be a number")); + let num = num_str + .parse::() + .unwrap_or_else(|_| output::die("Run number must be a number")); (name.to_string(), num) } else { let num = match cmd.get_one::("run_number").copied() { @@ -123,9 +147,12 @@ pub async fn do_logs(config: Config, cmd: &ArgMatches) { } pub async fn do_show(config: Config, cmd: &ArgMatches) { - let name = cmd.get_one::("app_name").expect("app_name is required"); + let name = cmd + .get_one::("app_name") + .expect("app_name is required"); + let env = cmd::get_string_flag(cmd, "environment"); - match api::describe_app(&config, &name).await { + match api::describe_app(&config, &name, Some(&env)).await { Ok(app_response) => { if output::get_output_mode().is_json() { output::json(&app_response); @@ -203,11 +230,11 @@ pub async fn do_show(config: Config, cmd: &ArgMatches) { } } -pub async fn do_list_apps(config: Config) { - let resp = output::with_spinner("Listing apps", api::list_apps(&config)).await; +pub async fn do_list_apps(config: Config, args: &ArgMatches) { + let env = args.get_one::("environment").map(|s| s.as_str()); + let apps = output::with_spinner("Listing apps", api::list_apps(&config, env)).await; - let items = resp - .apps + let items = apps .iter() .map(|app_summary| { let app = &app_summary.app; @@ -219,7 +246,7 @@ pub async fn do_list_apps(config: Config) { format!("{}\n{}", output::title(&app.name), desc) }) .collect(); - output::list(items, Some(&resp.apps)); + output::list(items, Some(&apps)); } pub async fn do_create(config: Config, args: &ArgMatches) { @@ -236,7 +263,9 @@ pub async fn do_create(config: Config, args: &ArgMatches) { } pub async fn do_delete(config: Config, cmd: &ArgMatches) { - let name = cmd.get_one::("app_name").expect("app_name is required"); + let name = cmd + .get_one::("app_name") + .expect("app_name is required"); output::with_spinner("Deleting app", api::delete_app(&config, name)).await; } @@ -262,8 +291,9 @@ pub async fn do_cancel(config: Config, cmd: &ArgMatches) { } async fn latest_run_number(config: &Config, name: &str) -> i64 { - match api::describe_app(config, name).await { - Ok(resp) => resp.runs + match api::describe_app(config, name, None).await { + Ok(resp) => resp + .runs .iter() .map(|r| r.number) .max() @@ -307,7 +337,9 @@ async fn follow_logs(config: Config, name: String, seq: i64) { sleep(RUN_START_POLL_INTERVAL).await; if wait_started.elapsed() > RUN_START_TIMEOUT { - output::error("Timed out waiting for run to start. The runner may be unavailable."); + output::error( + "Timed out waiting for run to start. The runner may be unavailable.", + ); return; } @@ -552,9 +584,9 @@ fn is_run_finished(run: &Run) -> bool { fn is_run_started(run: &Run) -> bool { match run.status { - tower_api::models::run::Status::Scheduled | tower_api::models::run::Status::Pending => { - false - } + tower_api::models::run::Status::Scheduled + | tower_api::models::run::Status::Pending + | tower_api::models::run::Status::Starting => false, _ => true, } } @@ -585,7 +617,9 @@ mod tests { assert_eq!(cmd, "logs"); assert_eq!(sub_matches.get_one::("follow"), Some(&true)); assert_eq!( - sub_matches.get_one::("app_name").map(|s| s.as_str()), + sub_matches + .get_one::("app_name") + .map(|s| s.as_str()), Some("hello-world#11") ); assert_eq!(sub_matches.get_one::("run_number"), None); @@ -599,7 +633,9 @@ mod tests { let (_, sub_matches) = matches.subcommand().unwrap(); assert_eq!( - sub_matches.get_one::("app_name").map(|s| s.as_str()), + sub_matches + .get_one::("app_name") + .map(|s| s.as_str()), Some("hello-world") ); assert_eq!(sub_matches.get_one::("run_number"), Some(&11)); @@ -607,7 +643,12 @@ mod tests { #[test] fn test_terminal_statuses_explicit() { - let non_terminal = [Status::Scheduled, Status::Pending, Status::Running, Status::Retrying]; + let non_terminal = [ + Status::Scheduled, + Status::Pending, + Status::Running, + Status::Retrying, + ]; for status in non_terminal { let run = Run { status, @@ -636,6 +677,7 @@ mod tests { let status = Status::Scheduled; match status { Status::Scheduled => {} + Status::Starting => {} Status::Pending => {} Status::Running => {} Status::Retrying => {} @@ -648,7 +690,7 @@ mod tests { #[test] fn test_run_started_statuses() { - let not_started = [Status::Scheduled, Status::Pending]; + let not_started = [Status::Scheduled, Status::Pending, Status::Starting]; for status in not_started { let run = Run { status, @@ -788,4 +830,53 @@ mod tests { let result = apps_cmd().try_get_matches_from(["apps", "cancel"]); assert!(result.is_err()); } + + #[test] + fn list_defaults_to_no_environment_filter() { + let matches = apps_cmd() + .try_get_matches_from(["apps", "list"]) + .unwrap(); + let (_, list_args) = matches.subcommand().unwrap(); + + assert_eq!(list_args.get_one::("environment"), None); + } + + #[test] + fn list_accepts_environment_flag() { + let matches = apps_cmd() + .try_get_matches_from(["apps", "list", "-e", "production"]) + .unwrap(); + let (_, list_args) = matches.subcommand().unwrap(); + + assert_eq!( + list_args.get_one::("environment").map(|s| s.as_str()), + Some("production") + ); + } + + #[test] + fn show_defaults_to_default_environment() { + let matches = apps_cmd() + .try_get_matches_from(["apps", "show", "my-app"]) + .unwrap(); + let (_, show_args) = matches.subcommand().unwrap(); + + assert_eq!( + show_args.get_one::("environment").unwrap(), + "default" + ); + } + + #[test] + fn show_accepts_environment_flag() { + let matches = apps_cmd() + .try_get_matches_from(["apps", "show", "my-app", "-e", "production"]) + .unwrap(); + let (_, show_args) = matches.subcommand().unwrap(); + + assert_eq!( + show_args.get_one::("environment").unwrap(), + "production" + ); + } } diff --git a/crates/tower-cmd/src/catalogs.rs b/crates/tower-cmd/src/catalogs.rs index 034e650a..06fb87f2 100644 --- a/crates/tower-cmd/src/catalogs.rs +++ b/crates/tower-cmd/src/catalogs.rs @@ -54,15 +54,14 @@ pub async fn do_list(config: Config, args: &ArgMatches) { let all = cmd::get_bool_flag(args, "all"); let env = cmd::get_string_flag(args, "environment"); - let list_response = + let catalogs = output::with_spinner("Listing catalogs", api::list_catalogs(&config, &env, all)).await; let headers = vec!["Name", "Type", "Environment"] .into_iter() .map(str::to_string) .collect(); - let data = list_response - .catalogs + let data = catalogs .iter() .map(|catalog| { vec![ @@ -72,7 +71,7 @@ pub async fn do_list(config: Config, args: &ArgMatches) { ] }) .collect(); - output::table(headers, data, Some(&list_response.catalogs)); + output::table(headers, data, Some(&catalogs)); } pub async fn do_show(config: Config, args: &ArgMatches) { diff --git a/crates/tower-cmd/src/deploy.rs b/crates/tower-cmd/src/deploy.rs index 069c1ca9..c5328f38 100644 --- a/crates/tower-cmd/src/deploy.rs +++ b/crates/tower-cmd/src/deploy.rs @@ -106,12 +106,11 @@ pub async fn deploy_from_dir( let path = dir.join("Towerfile"); let path_display = path.display().to_string(); - let towerfile = Towerfile::from_path(path).map_err(|source| { - crate::Error::TowerfileLoadFailed { + let towerfile = + Towerfile::from_path(path).map_err(|source| crate::Error::TowerfileLoadFailed { path: path_display, source, - } - })?; + })?; let api_config = config.into(); // Add app existence check before proceeding diff --git a/crates/tower-cmd/src/environments.rs b/crates/tower-cmd/src/environments.rs index 970677e4..a9dfad37 100644 --- a/crates/tower-cmd/src/environments.rs +++ b/crates/tower-cmd/src/environments.rs @@ -23,18 +23,18 @@ pub fn environments_cmd() -> Command { } pub async fn do_list(config: Config) { - let resp = output::with_spinner("Listing environments", api::list_environments(&config)).await; + let environments = + output::with_spinner("Listing environments", api::list_environments(&config)).await; let headers = vec!["Name".to_string()]; - let envs_data: Vec> = resp - .environments + let envs_data: Vec> = environments .iter() .map(|env| vec![env.name.clone()]) .collect(); // Display the table using the existing table function - output::table(headers, envs_data, Some(&resp.environments)); + output::table(headers, envs_data, Some(&environments)); } pub async fn do_create(config: Config, args: &ArgMatches) { diff --git a/crates/tower-cmd/src/lib.rs b/crates/tower-cmd/src/lib.rs index e42789b7..3560d3c4 100644 --- a/crates/tower-cmd/src/lib.rs +++ b/crates/tower-cmd/src/lib.rs @@ -30,6 +30,8 @@ pub struct App { impl App { pub fn new() -> Self { + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + let cmd = root_cmd(); // When TOWER_API_KEY is set, skip session entirely — the API key is self-contained @@ -123,7 +125,7 @@ impl App { let apps_command = sub_matches.subcommand(); match apps_command { - Some(("list", _)) => apps::do_list_apps(sessionized_config).await, + Some(("list", args)) => apps::do_list_apps(sessionized_config, args).await, Some(("create", args)) => apps::do_create(sessionized_config, args).await, Some(("show", args)) => apps::do_show(sessionized_config, args).await, Some(("logs", args)) => apps::do_logs(sessionized_config, args).await, @@ -249,6 +251,37 @@ fn root_cmd() -> Command { .value_parser(value_parser!(String)) .action(clap::ArgAction::Set), ) + .arg( + Arg::new("page_size") + .long("page-size") + .hide(true) + .value_parser(value_parser!(i64)) + .action(clap::ArgAction::Set) + .global(true), + ) + .arg( + Arg::new("no_paginate") + .long("no-paginate") + .help("Fetch only the first page of paginated results") + .action(clap::ArgAction::SetTrue) + .global(true), + ) + .arg( + Arg::new("max_items") + .long("max-items") + .help("Maximum number of items to return from paginated list commands") + .value_parser(value_parser!(i64)) + .action(clap::ArgAction::Set) + .global(true), + ) + .arg( + Arg::new("page") + .long("page") + .help("Page number to start at for paginated list commands; 0 (the default) requests all results without pagination") + .value_parser(value_parser!(i64)) + .action(clap::ArgAction::Set) + .global(true), + ) .subcommand_required(false) .arg_required_else_help(false) .subcommand(session::login_cmd()) diff --git a/crates/tower-cmd/src/mcp.rs b/crates/tower-cmd/src/mcp.rs index d46ba454..aeedb285 100644 --- a/crates/tower-cmd/src/mcp.rs +++ b/crates/tower-cmd/src/mcp.rs @@ -159,6 +159,44 @@ struct RunRequest { #[serde(flatten)] common: CommonParams, parameters: Option>, + /// The environment to run the app in (defaults to "default") + environment: Option, +} + +#[derive(Debug, Deserialize, JsonSchema)] +struct DeployRequest { + #[serde(flatten)] + common: CommonParams, + /// The environment to deploy to (defaults to "default") + environment: Option, +} + +#[derive(Debug, Deserialize, JsonSchema)] +struct ListAppsRequest { + /// Filter apps by environment. If not provided, apps across all environments are returned. + environment: Option, +} + +#[derive(Debug, Deserialize, JsonSchema)] +struct ShowAppRequest { + /// Name of the app + name: String, + /// The environment to resolve the app against (defaults to "default") + environment: Option, +} + +#[derive(Debug, Deserialize, JsonSchema)] +struct ListCatalogsRequest { + /// The environment to list catalogs from (defaults to "default") + environment: Option, +} + +#[derive(Debug, Deserialize, JsonSchema)] +struct ShowCatalogRequest { + /// Name of the catalog + name: String, + /// The environment the catalog belongs to (defaults to "default") + environment: Option, } pub fn mcp_cmd() -> Command { @@ -335,15 +373,14 @@ impl TowerService { } async fn list_teams_via_api(&self) -> Result { - let response = api::list_teams(&self.config).await.map_err(|e| { + let teams = api::list_teams(&self.config).await.map_err(|e| { McpError::internal_error( "Failed to list teams", Some(json!({"error": e.to_string()})), ) })?; - let teams: Vec = response - .teams + let teams: Vec = teams .into_iter() .map(|team| json!({"name": team.name})) .collect(); @@ -465,17 +502,21 @@ impl TowerService { // share constants directly. MCP-only descriptions (with Prerequisites/Optional) are // intentionally more detailed and don't need a CLI counterpart. #[tool(description = "List all apps in your Tower account")] - async fn tower_apps_list(&self) -> Result { - match api::list_apps(&self.config).await { - Ok(response) => { - let apps: Vec = response - .apps + async fn tower_apps_list( + &self, + Parameters(request): Parameters, + ) -> Result { + let environment = request.environment.as_deref(); + match api::list_apps(&self.config, environment).await { + Ok(apps) => { + let apps: Vec = apps .into_iter() .map(|app_summary| { let app = app_summary.app; json!({ "name": app.name, "description": app.short_description, + "version": app.version, "created_at": app.created_at, "status": format!("{:?}", app.status) }) @@ -501,9 +542,10 @@ impl TowerService { #[tool(description = "Show details for a Tower app and its recent runs")] async fn tower_apps_show( &self, - Parameters(request): Parameters, + Parameters(request): Parameters, ) -> Result { - match api::describe_app(&self.config, &request.name).await { + let environment = request.environment.as_deref().unwrap_or("default"); + match api::describe_app(&self.config, &request.name, Some(environment)).await { Ok(response) => { let data = json!({ "app": { @@ -594,7 +636,7 @@ impl TowerService { let all = request.all.as_deref() == Some("true"); match api::list_secrets(&self.config, environment, all).await { - Ok(response) => Self::json_success(json!({"secrets": response.secrets})), + Ok(secrets) => Self::json_success(json!({"secrets": secrets})), Err(e) => Self::error_result("Failed to list secrets", e), } } @@ -659,6 +701,61 @@ impl TowerService { } } + #[tool(description = "List catalogs in your Tower account")] + async fn tower_catalogs_list( + &self, + Parameters(request): Parameters, + ) -> Result { + let environment = request.environment.as_deref().unwrap_or("default"); + match api::list_catalogs(&self.config, environment, false).await { + Ok(catalogs) => { + let catalogs: Vec = catalogs + .into_iter() + .map(|catalog| { + json!({ + "name": catalog.name, + "type": catalog.r#type, + "environment": catalog.environment, + }) + }) + .collect(); + Self::json_success(json!({"catalogs": catalogs})) + } + Err(e) => Self::error_result("Failed to list catalogs", e), + } + } + + #[tool(description = "Show details for a catalog, including its property names")] + async fn tower_catalogs_show( + &self, + Parameters(request): Parameters, + ) -> Result { + let environment = request.environment.as_deref().unwrap_or("default"); + match api::describe_catalog(&self.config, &request.name, environment).await { + Ok(response) => { + let catalog = &response.catalog; + let properties: Vec = catalog + .properties + .iter() + .map(|prop| { + json!({ + "name": prop.name, + "environment_variable": prop.environment_variable, + "preview": prop.preview, + }) + }) + .collect(); + Self::json_success(json!({ + "name": catalog.name, + "type": catalog.r#type, + "environment": catalog.environment, + "properties": properties, + })) + } + Err(e) => Self::error_result("Failed to show catalog", e), + } + } + #[tool(description = "List teams you belong to")] async fn tower_teams_list(&self) -> Result { if self.config.api_key.is_some() { @@ -705,14 +802,15 @@ impl TowerService { } #[tool( - description = "Deploy to Tower cloud. Prerequisites: Towerfile, tower_apps_create. Optional: working_directory." + description = "Deploy to Tower cloud. Prerequisites: Towerfile, tower_apps_create. Optional: working_directory, environment." )] async fn tower_deploy( &self, - Parameters(request): Parameters, + Parameters(request): Parameters, ) -> Result { let working_dir = Self::resolve_working_directory(&request.common); - let deploy_target = deploy::DeployTarget::Environment("default".to_string()); + let env = request.environment.unwrap_or_else(|| "default".to_string()); + let deploy_target = deploy::DeployTarget::Environment(env); match deploy::deploy_from_dir(self.config.clone(), working_dir, true, deploy_target).await { Ok(_) => Self::text_success("Deploy completed successfully".to_string()), @@ -772,7 +870,7 @@ impl TowerService { let config = self.config.clone(); let working_dir = Self::resolve_working_directory(&request.common); let path = working_dir; - let env = "default"; + let env = request.environment.unwrap_or_else(|| "default".to_string()); let params = request.parameters.unwrap_or_default(); // Load Towerfile to get app name @@ -784,7 +882,7 @@ impl TowerService { let app_name = towerfile.app.name.clone(); let (result, output) = Self::execute_with_streaming(&ctx, || { - run::do_run_remote(config, path, env, params, None, true) + run::do_run_remote(config, path, &env, params, None, true) }) .await; match result { @@ -859,12 +957,15 @@ impl TowerService { } let name = request.name.clone(); Self::modify_towerfile(&request.common, |tf| { - tf.set_parameter(&name, Parameter { - name: name.clone(), - description: request.description.unwrap_or_default(), - default: request.default.unwrap_or_default(), - hidden: request.hidden, - }); + tf.set_parameter( + &name, + Parameter { + name: name.clone(), + description: request.description.unwrap_or_default(), + default: request.default.unwrap_or_default(), + hidden: request.hidden, + }, + ); Ok(format!("Added parameter '{name}'")) }) } @@ -878,7 +979,10 @@ impl TowerService { ) -> Result { let name = request.name.clone(); Self::modify_towerfile(&request.common, |tf| { - let existing = tf.parameters.iter().find(|p| p.name == name) + let existing = tf + .parameters + .iter() + .find(|p| p.name == name) .ok_or_else(|| format!("Parameter '{name}' not found"))?; let target_name = request .new_name @@ -889,7 +993,9 @@ impl TowerService { } let param = Parameter { name: target_name, - description: request.description.unwrap_or_else(|| existing.description.clone()), + description: request + .description + .unwrap_or_else(|| existing.description.clone()), default: request.default.unwrap_or_else(|| existing.default.clone()), hidden: request.hidden.unwrap_or(existing.hidden), }; @@ -901,9 +1007,7 @@ impl TowerService { }) } - #[tool( - description = "Remove a parameter from the Towerfile. Optional: working_directory." - )] + #[tool(description = "Remove a parameter from the Towerfile. Optional: working_directory.")] async fn tower_file_remove_parameter( &self, Parameters(request): Parameters, @@ -1030,9 +1134,8 @@ IMPORTANT REMINDERS: #[tool(description = "List all schedules for apps")] async fn tower_schedules_list(&self) -> Result { match api::list_schedules(&self.config, None, None).await { - Ok(response) => { - let schedules = response - .schedules + Ok(schedules) => { + let schedules = schedules .into_iter() .map(|mut schedule| { if let Some(parameters) = schedule.parameters.as_mut() { diff --git a/crates/tower-cmd/src/run.rs b/crates/tower-cmd/src/run.rs index 64f6cd5d..be8050e6 100644 --- a/crates/tower-cmd/src/run.rs +++ b/crates/tower-cmd/src/run.rs @@ -107,10 +107,7 @@ pub async fn do_run(config: Config, args: &ArgMatches) { /// do_run is the primary entrypoint into running apps both locally and remotely in Tower. It will /// use the configuration to determine the requested way of running a Tower app. -pub async fn do_run_inner( - config: Config, - args: &ArgMatches, -) -> Result<(), Error> { +pub async fn do_run_inner(config: Config, args: &ArgMatches) -> Result<(), Error> { let res = get_run_parameters(args); // We always expect there to be an environment due to the fact that there is a @@ -254,13 +251,22 @@ where output::error(&format!("Your local run crashed with exit code: {}", code)); return Err(Error::AppCrashed); } - Status::Failed { - error_code, - error_message, - } => { + Status::Cancelled => { + output::error("Your local run was cancelled."); + return Err(Error::AppCrashed); + } + Status::Failed(failure) => { + let detail = match failure { + tower_runtime::AppFailure::Runtime(e) => format!("{:?}", e), + tower_runtime::AppFailure::Panic(msg) => format!("panic: {}", msg), + tower_runtime::AppFailure::Platform { + error_code, + error_message, + } => format!("{} ({})", error_message, error_code), + }; output::error(&format!( - "Your local run failed due to a platform error (code: {}, message: {})", - error_code, error_message + "Your local run failed due to a platform error: {}", + detail )); return Err(Error::AppCrashed); } @@ -855,7 +861,10 @@ mod tests { #[test] fn app_name_parsed_as_positional_arg() { let m = parse(&["my-app"]).unwrap(); - assert_eq!(m.get_one::("app_name").map(|s| s.as_str()), Some("my-app")); + assert_eq!( + m.get_one::("app_name").map(|s| s.as_str()), + Some("my-app") + ); } #[test] @@ -868,8 +877,14 @@ mod tests { fn unknown_flags_are_rejected() { let err = parse(&["--param", "x=y"]).unwrap_err(); let msg = err.to_string(); - assert!(msg.contains("--param"), "should mention the bad flag: {msg}"); - assert!(msg.contains("--parameter"), "should suggest the correct flag: {msg}"); + assert!( + msg.contains("--param"), + "should mention the bad flag: {msg}" + ); + assert!( + msg.contains("--parameter"), + "should suggest the correct flag: {msg}" + ); } #[test] @@ -887,7 +902,10 @@ mod tests { #[test] fn parameters_after_app_name() { let m = parse(&["my-app", "-p", "key=val"]).unwrap(); - assert_eq!(m.get_one::("app_name").map(|s| s.as_str()), Some("my-app")); + assert_eq!( + m.get_one::("app_name").map(|s| s.as_str()), + Some("my-app") + ); let params: Vec<&String> = m.get_many::("parameters").unwrap().collect(); assert_eq!(params, vec!["key=val"]); } @@ -895,7 +913,10 @@ mod tests { #[test] fn parameters_before_app_name() { let m = parse(&["-p", "key=val", "my-app"]).unwrap(); - assert_eq!(m.get_one::("app_name").map(|s| s.as_str()), Some("my-app")); + assert_eq!( + m.get_one::("app_name").map(|s| s.as_str()), + Some("my-app") + ); let params: Vec<&String> = m.get_many::("parameters").unwrap().collect(); assert_eq!(params, vec!["key=val"]); } diff --git a/crates/tower-cmd/src/schedules.rs b/crates/tower-cmd/src/schedules.rs index 59562cf2..3fafd1d9 100644 --- a/crates/tower-cmd/src/schedules.rs +++ b/crates/tower-cmd/src/schedules.rs @@ -114,13 +114,13 @@ pub async fn do_list(config: Config, args: &ArgMatches) { let app = args.get_one::("app").map(|s| s.as_str()); let environment = args.get_one::("environment").map(|s| s.as_str()); - let response = output::with_spinner( + let schedules = output::with_spinner( "Listing schedules", api::list_schedules(&config, app, environment), ) .await; - if response.schedules.is_empty() { + if schedules.is_empty() { output::write("No schedules found.\n"); return; } @@ -130,8 +130,7 @@ pub async fn do_list(config: Config, args: &ArgMatches) { .map(str::to_string) .collect(); - let rows: Vec> = response - .schedules + let rows: Vec> = schedules .iter() .map(|schedule| { let status = match schedule.status { @@ -149,7 +148,7 @@ pub async fn do_list(config: Config, args: &ArgMatches) { }) .collect(); - output::table(headers, rows, Some(&response.schedules)); + output::table(headers, rows, Some(&schedules)); } pub async fn do_create(config: Config, args: &ArgMatches) { @@ -171,7 +170,9 @@ pub async fn do_create(config: Config, args: &ArgMatches) { } pub async fn do_update(config: Config, args: &ArgMatches) { - let id_or_name = args.get_one::("id_or_name").expect("id_or_name is required"); + let id_or_name = args + .get_one::("id_or_name") + .expect("id_or_name is required"); let cron = args.get_one::("cron"); let parameters = parse_parameters(args); @@ -185,7 +186,9 @@ pub async fn do_update(config: Config, args: &ArgMatches) { } pub async fn do_delete(config: Config, args: &ArgMatches) { - let schedule_id = args.get_one::("schedule_id").expect("schedule_id is required"); + let schedule_id = args + .get_one::("schedule_id") + .expect("schedule_id is required"); output::with_spinner( "Deleting schedule", diff --git a/crates/tower-cmd/src/secrets.rs b/crates/tower-cmd/src/secrets.rs index e6a95393..16c67009 100644 --- a/crates/tower-cmd/src/secrets.rs +++ b/crates/tower-cmd/src/secrets.rs @@ -133,15 +133,14 @@ pub async fn do_list(config: Config, args: &ArgMatches) { .collect(); output::table(headers, data, Some(&list_response.secrets)); } else { - let list_response = + let secrets = output::with_spinner("Listing secrets", api::list_secrets(&config, &env, all)).await; let headers = vec!["Secret", "Environment", "Preview"] .into_iter() .map(str::to_string) .collect(); - let data = list_response - .secrets + let data = secrets .iter() .map(|secret| { vec![ @@ -151,7 +150,7 @@ pub async fn do_list(config: Config, args: &ArgMatches) { ] }) .collect(); - output::table(headers, data, Some(&list_response.secrets)); + output::table(headers, data, Some(&secrets)); } } @@ -185,11 +184,15 @@ pub async fn do_create(config: Config, args: &ArgMatches) { } pub async fn do_delete(config: Config, args: &ArgMatches) { - let secret_name_arg = args.get_one::("secret_name").expect("secret_name is required"); + let secret_name_arg = args + .get_one::("secret_name") + .expect("secret_name is required"); let (environment, name) = if let Some((env, name)) = secret_name_arg.split_once('/') { (env.to_string(), name.to_string()) } else { - let env = args.get_one::("environment").expect("environment has default"); + let env = args + .get_one::("environment") + .expect("environment has default"); (env.clone(), secret_name_arg.clone()) }; debug!("deleting secret, environment={} name={}", environment, name); @@ -240,4 +243,3 @@ async fn encrypt_and_create_secret( .await .map_err(SecretCreationError::CreateFailed) } - diff --git a/crates/tower-cmd/src/session.rs b/crates/tower-cmd/src/session.rs index 409d06cd..32d88987 100644 --- a/crates/tower-cmd/src/session.rs +++ b/crates/tower-cmd/src/session.rs @@ -33,7 +33,8 @@ pub async fn do_login(config: Config, args: &ArgMatches) { eprint!("Do you want to continue? [y/N] "); let mut input = String::new(); - if std::io::stdin().read_line(&mut input).is_err() || !input.trim().eq_ignore_ascii_case("y") + if std::io::stdin().read_line(&mut input).is_err() + || !input.trim().eq_ignore_ascii_case("y") { return; } diff --git a/crates/tower-cmd/src/skill.rs b/crates/tower-cmd/src/skill.rs index 13caca60..be1ee7b7 100644 --- a/crates/tower-cmd/src/skill.rs +++ b/crates/tower-cmd/src/skill.rs @@ -29,10 +29,7 @@ fn generate_skill_md(root: Command) -> String { } fn append_command(out: &mut String, cmd: &Command, path: &[&str], depth: usize) { - let subcommands: Vec<_> = cmd - .get_subcommands() - .filter(|c| !c.is_hide_set()) - .collect(); + let subcommands: Vec<_> = cmd.get_subcommands().filter(|c| !c.is_hide_set()).collect(); for sub in &subcommands { let name = sub.get_name(); @@ -71,12 +68,7 @@ fn append_command(out: &mut String, cmd: &Command, path: &[&str], depth: usize) .get_help() .map(|h| format!(" — {}", h)) .unwrap_or_default(); - out.push_str(&format!( - "- `<{}>` {}{}\n", - arg.get_id(), - req, - help - )); + out.push_str(&format!("- `<{}>` {}{}\n", arg.get_id(), req, help)); } for arg in &named { let long = arg.get_long().unwrap(); @@ -98,10 +90,7 @@ fn append_command(out: &mut String, cmd: &Command, path: &[&str], depth: usize) out.push('\n'); } - let child_subs: Vec<_> = sub - .get_subcommands() - .filter(|c| !c.is_hide_set()) - .collect(); + let child_subs: Vec<_> = sub.get_subcommands().filter(|c| !c.is_hide_set()).collect(); if !child_subs.is_empty() { append_command(out, sub, &full_path, depth + 1); diff --git a/crates/tower-cmd/src/teams.rs b/crates/tower-cmd/src/teams.rs index d0cc2413..36783a9e 100644 --- a/crates/tower-cmd/src/teams.rs +++ b/crates/tower-cmd/src/teams.rs @@ -56,12 +56,11 @@ pub async fn do_list(config: Config) { } async fn do_list_via_api(config: &Config) { - let resp = output::with_spinner("Fetching teams", api::list_teams(config)).await; + let teams = output::with_spinner("Fetching teams", api::list_teams(config)).await; let headers = vec!["Name".to_string()]; - let teams_data: Vec> = resp - .teams + let teams_data: Vec> = teams .iter() .map(|team| vec![team.name.clone()]) .collect(); @@ -109,7 +108,9 @@ async fn do_list_via_session(config: &Config) { } pub async fn do_switch(config: Config, args: &ArgMatches) { - let name = args.get_one::("team_name").expect("team_name is required"); + let name = args + .get_one::("team_name") + .expect("team_name is required"); // Refresh the session first to ensure we have the latest teams data let session = refresh_session(&config).await; @@ -140,4 +141,3 @@ pub async fn do_switch(config: Config, args: &ArgMatches) { } } } - diff --git a/crates/tower-cmd/src/util/apps.rs b/crates/tower-cmd/src/util/apps.rs index e6e14524..3b6cf49c 100644 --- a/crates/tower-cmd/src/util/apps.rs +++ b/crates/tower-cmd/src/util/apps.rs @@ -22,6 +22,7 @@ pub async fn ensure_app_exists( start_at: None, end_at: None, timezone: None, + environment: None, }, ) .await; diff --git a/crates/tower-cmd/src/util/deploy.rs b/crates/tower-cmd/src/util/deploy.rs index 5a6d3619..23c56a3c 100644 --- a/crates/tower-cmd/src/util/deploy.rs +++ b/crates/tower-cmd/src/util/deploy.rs @@ -8,8 +8,8 @@ use tower_package::{compute_sha256_file, Package}; use tower_telemetry::debug; use tower_api::apis::configuration::Configuration; -use tower_api::apis::urlencode; use tower_api::apis::default_api::DeployAppError; +use tower_api::apis::urlencode; use tower_api::apis::Error; use tower_api::apis::ResponseContent; use tower_api::models::DeployAppResponse; @@ -122,10 +122,16 @@ pub async fn deploy_app_package( let encoded_app_name = urlencode(app_name); let url = if all_environments { - format!("{}/apps/{}/deploy?all_environments=true", base_url, encoded_app_name) + format!( + "{}/apps/{}/deploy?all_environments=true", + base_url, encoded_app_name + ) } else if let Some(env) = environment { let encoded_environment = urlencode(env); - format!("{}/apps/{}/deploy?environment={}", base_url, encoded_app_name, encoded_environment) + format!( + "{}/apps/{}/deploy?environment={}", + base_url, encoded_app_name, encoded_environment + ) } else { format!("{}/apps/{}/deploy", base_url, encoded_app_name) }; diff --git a/crates/tower-package/src/core.rs b/crates/tower-package/src/core.rs index ed35e264..b376f83a 100644 --- a/crates/tower-package/src/core.rs +++ b/crates/tower-package/src/core.rs @@ -124,11 +124,10 @@ pub struct BuiltPackage { // normalized (mtime/uid/gid zero, mode 0644) so the output is byte-deterministic for a given // input. pub fn build_package(inputs: PackageInputs) -> Result { - let towerfile_str = std::str::from_utf8(&inputs.towerfile_bytes).map_err(|e| { - Error::InvalidTowerfile { + let towerfile_str = + std::str::from_utf8(&inputs.towerfile_bytes).map_err(|e| Error::InvalidTowerfile { message: format!("Towerfile is not valid UTF-8: {}", e), - } - })?; + })?; let towerfile = Towerfile::from_toml(towerfile_str)?; let import_paths: Vec = towerfile @@ -138,14 +137,18 @@ pub fn build_package(inputs: PackageInputs) -> Result { .map(|p| format!("modules/{}", import_path_basename(&p.to_string_lossy()))) .collect(); - let mut entries: Vec = Vec::with_capacity(inputs.app_files.len() + inputs.module_files.len()); + let mut entries: Vec = + Vec::with_capacity(inputs.app_files.len() + inputs.module_files.len()); entries.extend(inputs.app_files); entries.extend(inputs.module_files); entries.sort_by(|a, b| a.archive_name.cmp(&b.archive_name)); let mut path_hashes: HashMap = HashMap::with_capacity(entries.len()); for entry in &entries { - path_hashes.insert(entry.archive_name.clone(), compute_sha256_bytes(&entry.bytes)); + path_hashes.insert( + entry.archive_name.clone(), + compute_sha256_bytes(&entry.bytes), + ); } let manifest = Manifest { @@ -256,15 +259,24 @@ mod test { .join("path") .join("to") .join("file.txt"); - assert_eq!(normalize_path(&path).unwrap(), "some/nested/path/to/file.txt"); + assert_eq!( + normalize_path(&path).unwrap(), + "some/nested/path/to/file.txt" + ); } #[test] fn test_build_package_is_deterministic() { let inputs = || PackageInputs { app_files: vec![ - Entry { archive_name: "app/b.py".into(), bytes: b"b".to_vec() }, - Entry { archive_name: "app/a.py".into(), bytes: b"a".to_vec() }, + Entry { + archive_name: "app/b.py".into(), + bytes: b"b".to_vec(), + }, + Entry { + archive_name: "app/a.py".into(), + bytes: b"a".to_vec(), + }, ], module_files: vec![], towerfile_bytes: b"[app]\nname = \"x\"\nscript = \"app/a.py\"\n".to_vec(), diff --git a/crates/tower-package/src/native.rs b/crates/tower-package/src/native.rs index e7a6d69a..0db79b38 100644 --- a/crates/tower-package/src/native.rs +++ b/crates/tower-package/src/native.rs @@ -150,7 +150,10 @@ impl Package { let archive_path = app_dir.join(logical_path); let archive_name = normalize_path(&archive_path)?; let bytes = tokio::fs::read(&physical_path).await?; - app_files.push(Entry { archive_name, bytes }); + app_files.push(Entry { + archive_name, + bytes, + }); } // Resolve modules. Archive names use the raw import_path basename so they stay in sync @@ -158,9 +161,13 @@ impl Package { let module_dir = PathBuf::from("modules"); let mut module_files: Vec = Vec::new(); - for (raw_import, canonical_import) in spec.import_paths.iter().zip(canonical_import_paths.iter()) { + for (raw_import, canonical_import) in + spec.import_paths.iter().zip(canonical_import_paths.iter()) + { let mut module_file_paths: HashMap = HashMap::new(); - resolver.resolve_path(canonical_import, &mut module_file_paths).await; + resolver + .resolve_path(canonical_import, &mut module_file_paths) + .await; let raw_basename = Path::new(raw_import) .file_name() @@ -175,7 +182,10 @@ impl Package { }; let archive_name = normalize_path(&archive_prefix.join(rel))?; let bytes = tokio::fs::read(&physical_path).await?; - module_files.push(Entry { archive_name, bytes }); + module_files.push(Entry { + archive_name, + bytes, + }); } } diff --git a/crates/tower-package/src/towerfile.rs b/crates/tower-package/src/towerfile.rs index e0de3b29..f86b2d53 100644 --- a/crates/tower-package/src/towerfile.rs +++ b/crates/tower-package/src/towerfile.rs @@ -134,9 +134,10 @@ impl Towerfile { use crate::error::Error as OuterError; let target_path = path.unwrap_or_else(|| std::path::Path::new("Towerfile")); - let serialized = toml::to_string_pretty(self).map_err(|err| OuterError::InvalidTowerfile { - message: err.to_string(), - })?; + let serialized = + toml::to_string_pretty(self).map_err(|err| OuterError::InvalidTowerfile { + message: err.to_string(), + })?; std::fs::write(target_path, serialized).map_err(|source| OuterError::Io { source })?; Ok(()) } @@ -315,12 +316,15 @@ mod test { let mut towerfile = crate::Towerfile::default(); assert_eq!(towerfile.parameters.len(), 0); - towerfile.set_parameter("test-param", crate::Parameter { - name: "test-param".to_string(), - description: "A test parameter".to_string(), - default: "default-value".to_string(), - hidden: false, - }); + towerfile.set_parameter( + "test-param", + crate::Parameter { + name: "test-param".to_string(), + description: "A test parameter".to_string(), + default: "default-value".to_string(), + hidden: false, + }, + ); assert_eq!(towerfile.parameters.len(), 1); assert_eq!(towerfile.parameters[0].name, "test-param"); @@ -329,12 +333,15 @@ mod test { assert!(!towerfile.parameters[0].hidden); // upsert should replace, not duplicate - towerfile.set_parameter("test-param", crate::Parameter { - name: "test-param".to_string(), - description: "Updated".to_string(), - default: "new-value".to_string(), - hidden: false, - }); + towerfile.set_parameter( + "test-param", + crate::Parameter { + name: "test-param".to_string(), + description: "Updated".to_string(), + default: "new-value".to_string(), + hidden: false, + }, + ); assert_eq!(towerfile.parameters.len(), 1); assert_eq!(towerfile.parameters[0].description, "Updated"); @@ -343,12 +350,15 @@ mod test { #[test] fn test_remove_parameter() { let mut towerfile = crate::Towerfile::default(); - towerfile.set_parameter("param1", crate::Parameter { - name: "param1".to_string(), - description: "".to_string(), - default: "".to_string(), - hidden: false, - }); + towerfile.set_parameter( + "param1", + crate::Parameter { + name: "param1".to_string(), + description: "".to_string(), + default: "".to_string(), + hidden: false, + }, + ); assert!(towerfile.remove_parameter("param1")); assert_eq!(towerfile.parameters.len(), 0); diff --git a/crates/tower-package/src/wasm.rs b/crates/tower-package/src/wasm.rs index 0649f327..219fbd3d 100644 --- a/crates/tower-package/src/wasm.rs +++ b/crates/tower-package/src/wasm.rs @@ -1,5 +1,5 @@ -use serde::Deserialize; use crate::core::{build_package, Entry, PackageInputs}; +use serde::Deserialize; use wasm_bindgen::prelude::*; #[derive(Deserialize)] @@ -52,7 +52,7 @@ pub fn build_package_wasm(inputs: JsValue) -> Result, JsError> { towerfile_bytes: js.towerfile_bytes.into_vec(), }; - let built = build_package(core_inputs) - .map_err(|e| JsError::new(&format!("build failed: {}", e)))?; + let built = + build_package(core_inputs).map_err(|e| JsError::new(&format!("build failed: {}", e)))?; Ok(built.bytes) } diff --git a/crates/tower-package/tests/package_test.rs b/crates/tower-package/tests/package_test.rs index 2eeef5c1..e39a020f 100644 --- a/crates/tower-package/tests/package_test.rs +++ b/crates/tower-package/tests/package_test.rs @@ -259,12 +259,14 @@ async fn it_packages_import_paths() { ); // Let's decode the manifest and make sure import paths are set correctly. - let manifest = Manifest::from_json(files.get("MANIFEST").unwrap()) - .expect("Manifest was not valid JSON"); + let manifest = + Manifest::from_json(files.get("MANIFEST").unwrap()).expect("Manifest was not valid JSON"); // Archive paths are always normalized to forward slashes regardless of OS. assert!( - manifest.import_paths.contains(&"modules/shared".to_string()), + manifest + .import_paths + .contains(&"modules/shared".to_string()), "Import paths {:?} did not contain expected path", manifest.import_paths ); @@ -323,11 +325,13 @@ async fn it_packages_import_paths_nested_within_base_dir() { ); // Verify the manifest import_paths entry matches the actual package structure. - let manifest = Manifest::from_json(files.get("MANIFEST").unwrap()) - .expect("Manifest was not valid JSON"); + let manifest = + Manifest::from_json(files.get("MANIFEST").unwrap()).expect("Manifest was not valid JSON"); assert!( - manifest.import_paths.contains(&"modules/shared".to_string()), + manifest + .import_paths + .contains(&"modules/shared".to_string()), "Import paths {:?} did not contain expected path modules/shared", manifest.import_paths ); @@ -425,7 +429,12 @@ async fn it_includes_subapp_towerfiles_but_excludes_root_towerfile() { create_test_file(tmp_dir.to_path_buf(), "main.py", "print('Hello, world!')").await; // Sub-app with its own Towerfile - create_test_file(tmp_dir.to_path_buf(), "subapp/Towerfile", "[app]\nname = \"subapp\"").await; + create_test_file( + tmp_dir.to_path_buf(), + "subapp/Towerfile", + "[app]\nname = \"subapp\"", + ) + .await; create_test_file(tmp_dir.to_path_buf(), "subapp/main.py", "print('subapp')").await; let spec = PackageSpec { @@ -506,15 +515,23 @@ hidden = true let package = Package::build(spec).await.expect("Failed to build package"); let files = read_package_files(package).await; - let manifest = Manifest::from_json(files.get("MANIFEST").unwrap()) - .expect("Manifest was not valid JSON"); + let manifest = + Manifest::from_json(files.get("MANIFEST").unwrap()).expect("Manifest was not valid JSON"); assert_eq!(manifest.parameters.len(), 2); - let visible = manifest.parameters.iter().find(|p| p.name == "visible_param").unwrap(); + let visible = manifest + .parameters + .iter() + .find(|p| p.name == "visible_param") + .unwrap(); assert!(!visible.hidden, "visible_param should not be hidden"); - let hidden = manifest.parameters.iter().find(|p| p.name == "hidden_param").unwrap(); + let hidden = manifest + .parameters + .iter() + .find(|p| p.name == "hidden_param") + .unwrap(); assert!(hidden.hidden, "hidden_param should be hidden"); assert_eq!(hidden.default, "secret"); } diff --git a/crates/tower-runtime/Cargo.toml b/crates/tower-runtime/Cargo.toml index 37b47f62..e28fab94 100644 --- a/crates/tower-runtime/Cargo.toml +++ b/crates/tower-runtime/Cargo.toml @@ -9,6 +9,7 @@ license = { workspace = true } [dependencies] async-trait = { workspace = true } chrono = { workspace = true } +futures = { workspace = true } nix = { workspace = true } snafu = { workspace = true } tmpdir = { workspace = true } diff --git a/crates/tower-runtime/src/errors.rs b/crates/tower-runtime/src/errors.rs index 0326cd27..75a6b09c 100644 --- a/crates/tower-runtime/src/errors.rs +++ b/crates/tower-runtime/src/errors.rs @@ -1,6 +1,6 @@ use snafu::prelude::*; -#[derive(Debug, Snafu)] +#[derive(Clone, Debug, PartialEq, Eq, Snafu)] pub enum Error { #[snafu(display("failed to RPC server"))] RuntimeStartFailed, diff --git a/crates/tower-runtime/src/lib.rs b/crates/tower-runtime/src/lib.rs index 6ebbb061..446264fe 100644 --- a/crates/tower-runtime/src/lib.rs +++ b/crates/tower-runtime/src/lib.rs @@ -45,9 +45,34 @@ pub enum Status { Crashed { code: i32, }, + /// The app was explicitly terminated via the `CancellationToken` — a + /// deliberate stop, not a failure or a crash. Distinct from `Crashed` + /// because there's no meaningful exit code to report. + Cancelled, /// A platform-level failure (not the user's app). For example, pod scheduling /// failures, image pull errors, or other infrastructure issues. - Failed { + Failed(AppFailure), +} + +/// A platform-level failure — distinct from a child-process crash +/// (`Status::Crashed`) because the user's app never ran to completion. +/// Consumers (currently `tower-runtime-entrypoint` and the runner-side k8s +/// backend) translate this into the `error_code` / `error_message` strings +/// that flow through the termination-log → control-plane log pipeline. +#[derive(Clone, Debug, PartialEq)] +pub enum AppFailure { + /// A structured runtime error from `tower_runtime` (e.g. + /// `UnsupportedPlatform`, `SpawnFailed`, `DependencyInstallationFailed`). + Runtime(Error), + /// A panic inside the spawned task. `catch_unwind` only returns + /// `Box`, so we surface the best-effort textual payload. + Panic(String), + /// A platform failure surfaced from outside `tower_runtime` (e.g. the + /// kubelet refusing to pull an image, an init container failing, or a + /// parsed entrypoint termination message). The `error_code` is opaque + /// to `tower_runtime` — the consumer that constructed this variant owns + /// the vocabulary. + Platform { error_code: String, error_message: String, }, @@ -56,7 +81,13 @@ pub enum Status { impl Status { /// Returns true if this status represents a terminal state (run is finished) pub fn is_terminal(&self) -> bool { - matches!(self, Status::Exited | Status::Crashed { .. } | Status::Failed { .. }) + matches!( + self, + Status::Exited + | Status::Crashed { .. } + | Status::Cancelled + | Status::Failed(_) + ) } } diff --git a/crates/tower-runtime/src/local.rs b/crates/tower-runtime/src/local.rs index 745c4b57..07b368cf 100644 --- a/crates/tower-runtime/src/local.rs +++ b/crates/tower-runtime/src/local.rs @@ -6,7 +6,7 @@ use std::process::Stdio; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; -use crate::{errors::Error, OutputSender, StartOptions, Status}; +use crate::{errors::Error, AppFailure, OutputSender, StartOptions, Status}; use tokio::{ fs, @@ -35,18 +35,51 @@ use tower_uv::Uv; use crate::{App, Channel, Output, FD}; +/// Result of running an app to completion. The spawned execution task always +/// sends one of these on its waiter channel before exiting, so `status()` can +/// distinguish a real platform failure from a closed channel. +/// +/// `Failed(AppFailure)` preserves the structured `Error` (or panic payload) +/// so consumers can act on the variant directly — `error_code` / `error_message` +/// stringification is the consumer's responsibility. +#[derive(Clone, Debug)] +enum AppCompletion { + /// Child process exited (0 = clean, non-zero = crashed). + Exit(i32), + /// The cancellation token fired — explicit termination, not a failure. + /// Distinct from `Exit(non_zero)` so consumers can tell a deliberate stop + /// apart from a real crash. + Cancelled, + /// Platform-level failure inside the spawned task before/around the child + /// process (e.g. `tower_uv::Error`, env join failure, panic). + Failed(AppFailure), +} + +/// Best-effort extraction of a panic message from a `catch_unwind` payload. +fn panic_payload_message(payload: &Box) -> String { + if let Some(s) = payload.downcast_ref::<&'static str>() { + (*s).to_string() + } else if let Some(s) = payload.downcast_ref::() { + s.clone() + } else { + "execute_local_app panicked with non-string payload".to_string() + } +} + pub struct LocalApp { status: Mutex>, // waiter is what we use to communicate that the overall process is finished by the execution - // handle. - waiter: Mutex>, + // handle. The spawned task always sends an `AppCompletion` before it ends; if the channel + // ever closes without a send, that's a real bug (task aborted, runtime dropped) and surfaces + // as `Error::WaiterClosed`. + waiter: Mutex>, // terminator is what we use to flag that we want to terminate the child process. terminator: CancellationToken, // execute_handle keeps track of the current state of the execution lifecycle. - execute_handle: Option>>, + execute_handle: Option>, } // Helper function to check if a file is executable @@ -99,11 +132,18 @@ async fn find_bash() -> Result { } } -async fn execute_local_app( +/// Run the app to completion, returning the child's exit code on success or an +/// `Error` for any platform failure. Cancellation is reported as `Ok(-1)` to +/// preserve the historical `Status::Crashed { code: -1 }` semantic. +/// +/// The caller is responsible for delivering the result on the waiter channel — +/// see `LocalApp::start`, which wraps this in `catch_unwind` and an unconditional +/// `sx.send(AppCompletion::...)` so that no failure path can silently close the +/// channel. +async fn inner_execute_local_app( opts: StartOptions, - sx: oneshot::Sender, cancel_token: CancellationToken, -) -> Result<(), Error> { +) -> Result { let ctx = opts.ctx.clone(); let package = opts.package; let environment = opts.environment; @@ -157,9 +197,6 @@ async fn execute_local_app( // We do this before instantiating `Uv` because that can be somewhat time consuming. Likewise // this stops us from instantiating a bash process. if cancel_token.is_cancelled() { - // if there's a waiter, we want them to know that the process was cancelled so we have - // to return something on the relevant channel. - let _ = sx.send(-1); return Err(Error::Cancelled); } @@ -176,7 +213,14 @@ async fn execute_local_app( ) .await?; - let _ = sx.send(wait_for_process(ctx.clone(), &cancel_token, child).await); + let code = wait_for_process(ctx.clone(), &cancel_token, child).await; + // `wait_for_process` returns -1 on both cancellation and IO error; + // disambiguate so a cancellation surfaces as `Status::Cancelled` + // rather than `Status::Crashed { code: -1 }`. + if cancel_token.is_cancelled() { + return Err(Error::Cancelled); + } + Ok(code) } else { // we put Uv in to protected mode when there's no caching configured/enabled. let protected_mode = opts.cache_dir.is_none(); @@ -197,8 +241,6 @@ async fn execute_local_app( // Quickly do a check to see if there was a cancellation before we do a subprocess spawn to // ensure everything is in place. if cancel_token.is_cancelled() { - // again tell any waiters that we cancelled. - let _ = sx.send(-1); return Err(Error::Cancelled); } @@ -224,17 +266,21 @@ async fn execute_local_app( // Wait for venv to finish up. let res = wait_for_process(ctx.clone(), &cancel_token, child).await; + // Distinguish cancellation from a real uv-venv non-zero exit. + if cancel_token.is_cancelled() { + return Err(Error::Cancelled); + } + if res != 0 { - // If the venv process failed, we want to return an error. - let _ = sx.send(res); - return Err(Error::VirtualEnvCreationFailed); + // `uv venv` exited non-zero — surface as a crash with the child's + // exit code. `Status::Failed` is reserved for platform errors + // where the child never ran at all. + return Ok(res); } // Check once more if the process was cancelled before we do a uv sync. The sync itself, // once started, will take a while and we have logic for checking for cancellation. if cancel_token.is_cancelled() { - // again tell any waiters that we cancelled. - let _ = sx.send(-1); return Err(Error::Cancelled); } @@ -256,33 +302,22 @@ async fn execute_local_app( } } } - Ok(mut child) => { - // Drain the logs to the output channel. - let stdout = child.stdout.take().expect("no stdout"); - tokio::spawn(drain_output( - FD::Stdout, - Channel::Setup, - opts.output_sender.clone(), - BufReader::new(stdout), - )); - - let stderr = child.stderr.take().expect("no stderr"); - tokio::spawn(drain_output( - FD::Stderr, - Channel::Setup, - opts.output_sender.clone(), - BufReader::new(stderr), - )); - - // Let's wait for the setup to finish. We don't care about the results. - let mut res = wait_for_process(ctx.clone(), &cancel_token, child).await; - - // If the requirements.txt install failed, retry with the legacy - // setuptools<82 pin. Some apps (those whose transitive deps rely on + Ok(child) => { + let mut res = run_setup_child(&ctx, &cancel_token, &opts.output_sender, child).await; + + // If sync was cancelled, don't bother retrying — bail out + // cleanly so the receiver sees `Status::Cancelled` instead of + // `Status::Crashed { code: -1 }`. + if cancel_token.is_cancelled() { + return Err(Error::Cancelled); + } + + // If the install failed, retry with the legacy setuptools<82 + // pin. Some apps (those whose transitive deps rely on // pkg_resources) need that pin to install successfully; we don't // apply it by default because it conflicts with apps whose deps // require setuptools>=82. - if res != 0 && uv.should_use_legacy_setuptools_pin(&working_dir) { + if res != 0 { let _ = opts.output_sender.send(Output { channel: Channel::Setup, fd: FD::Stdout, @@ -290,48 +325,26 @@ async fn execute_local_app( time: chrono::Utc::now(), }); - match uv + let retry_child = uv .sync_with_legacy_setuptools_pin(&working_dir, &env_vars) - .await - { - Err(e) => { - return Err(e.into()); - } - Ok(mut retry_child) => { - let stdout = retry_child.stdout.take().expect("no stdout"); - tokio::spawn(drain_output( - FD::Stdout, - Channel::Setup, - opts.output_sender.clone(), - BufReader::new(stdout), - )); - - let stderr = retry_child.stderr.take().expect("no stderr"); - tokio::spawn(drain_output( - FD::Stderr, - Channel::Setup, - opts.output_sender.clone(), - BufReader::new(stderr), - )); - - res = wait_for_process(ctx.clone(), &cancel_token, retry_child).await; - } + .await?; + res = run_setup_child(&ctx, &cancel_token, &opts.output_sender, retry_child).await; + if cancel_token.is_cancelled() { + return Err(Error::Cancelled); } } if res != 0 { - // If the sync process failed, we want to return an error. - let _ = sx.send(res); - return Err(Error::DependencyInstallationFailed); + // `uv sync` exited non-zero — surface as a crash with the + // child's exit code. `Status::Failed` is reserved for + // platform errors where the child never ran at all. + return Ok(res); } } } // Check once more to see if the process was cancelled, this will bail us out early. if cancel_token.is_cancelled() { - // if there's a waiter, we want them to know that the process was cancelled so we have - // to return something on the relevant channel. - let _ = sx.send(-1); return Err(Error::Cancelled); } @@ -354,11 +367,12 @@ async fn execute_local_app( BufReader::new(stderr), )); - let _ = sx.send(wait_for_process(ctx.clone(), &cancel_token, child).await); + let code = wait_for_process(ctx.clone(), &cancel_token, child).await; + if cancel_token.is_cancelled() { + return Err(Error::Cancelled); + } + Ok(code) } - - // Everything was properly executed I suppose. - return Ok(()); } impl Drop for LocalApp { @@ -379,12 +393,36 @@ impl Drop for LocalApp { impl App for LocalApp { async fn start(opts: StartOptions) -> Result { + use futures::FutureExt; + use std::panic::AssertUnwindSafe; + let terminator = CancellationToken::new(); - let (sx, rx) = oneshot::channel::(); + let (sx, rx) = oneshot::channel::(); let waiter = Mutex::new(rx); - let handle = tokio::spawn(execute_local_app(opts, sx, terminator.clone())); + let task_terminator = terminator.clone(); + let handle = tokio::spawn(async move { + // `catch_unwind` turns a panic inside the spawned task into a normal + // `Err(payload)` so we can still report it on the waiter channel + // instead of leaving the receiver to observe a silently-closed + // channel (the historical `WaiterClosed` bug). + // + // `Err(Error::Cancelled)` is special-cased: cancellation is a + // deliberate stop, not a failure, so it surfaces as + // `AppCompletion::Cancelled` → `Status::Cancelled` rather than + // `AppCompletion::Failed(AppFailure::Runtime(Error::Cancelled))`. + let completion = match AssertUnwindSafe(inner_execute_local_app(opts, task_terminator)) + .catch_unwind() + .await + { + Ok(Ok(code)) => AppCompletion::Exit(code), + Ok(Err(Error::Cancelled)) => AppCompletion::Cancelled, + Ok(Err(e)) => AppCompletion::Failed(AppFailure::Runtime(e)), + Err(panic) => AppCompletion::Failed(AppFailure::Panic(panic_payload_message(&panic))), + }; + let _ = sx.send(completion); + }); let execute_handle = Some(handle); Ok(Self { @@ -418,17 +456,28 @@ impl App for LocalApp { match res { Err(TryRecvError::Empty) => Ok(Status::Running), + // The spawned task always sends an `AppCompletion` before + // exiting, so a closed channel here means the task was + // aborted or the runtime dropped — a real bug worth + // surfacing as-is. Err(TryRecvError::Closed) => Err(Error::WaiterClosed), - Ok(t) => { - // We save this for the next time this gets called. - if t == 0 { - *status = Some(Status::Exited); - Ok(Status::Exited) - } else { - let next_status = Status::Crashed { code: t }; - *status = Some(next_status.clone()); - Ok(next_status) - } + Ok(AppCompletion::Exit(0)) => { + *status = Some(Status::Exited); + Ok(Status::Exited) + } + Ok(AppCompletion::Exit(code)) => { + let next_status = Status::Crashed { code }; + *status = Some(next_status.clone()); + Ok(next_status) + } + Ok(AppCompletion::Cancelled) => { + *status = Some(Status::Cancelled); + Ok(Status::Cancelled) + } + Ok(AppCompletion::Failed(failure)) => { + let next_status = Status::Failed(failure); + *status = Some(next_status.clone()); + Ok(next_status) } } } @@ -574,6 +623,31 @@ async fn kill_child_process(ctx: &tower_telemetry::Context, mut child: Child) { }; } +async fn run_setup_child( + ctx: &tower_telemetry::Context, + cancel_token: &CancellationToken, + output_sender: &OutputSender, + mut child: Child, +) -> i32 { + let stdout = child.stdout.take().expect("no stdout"); + tokio::spawn(drain_output( + FD::Stdout, + Channel::Setup, + output_sender.clone(), + BufReader::new(stdout), + )); + + let stderr = child.stderr.take().expect("no stderr"); + tokio::spawn(drain_output( + FD::Stderr, + Channel::Setup, + output_sender.clone(), + BufReader::new(stderr), + )); + + wait_for_process(ctx.clone(), cancel_token, child).await +} + async fn wait_for_process( ctx: tower_telemetry::Context, cancel_token: &CancellationToken, diff --git a/crates/tower-runtime/tests/local_test.rs b/crates/tower-runtime/tests/local_test.rs index 5dda4d9d..b0ab679a 100644 --- a/crates/tower-runtime/tests/local_test.rs +++ b/crates/tower-runtime/tests/local_test.rs @@ -373,6 +373,9 @@ async fn test_abort_on_dependency_installation_failure() { Status::None => { panic!("App should have a status"); } + Status::Cancelled => { + panic!("App should have crashed, not been cancelled"); + } Status::Failed { .. } => { panic!("App should have crashed, not failed with a platform error"); } diff --git a/crates/tower-telemetry/src/logging.rs b/crates/tower-telemetry/src/logging.rs index 021e9cb9..1b717f70 100644 --- a/crates/tower-telemetry/src/logging.rs +++ b/crates/tower-telemetry/src/logging.rs @@ -179,7 +179,11 @@ fn should_use_color(destination: &LogDestination) -> bool { } } -fn create_fmt_layer(level: &LogLevel, format: LogFormat, destination: LogDestination) -> BoxedFmtLayer { +fn create_fmt_layer( + level: &LogLevel, + format: LogFormat, + destination: LogDestination, +) -> BoxedFmtLayer { let use_color = should_use_color(&destination); let with_target = *level < LogLevel::Warn; @@ -242,7 +246,8 @@ pub fn enable_logging(level: LogLevel, format: LogFormat, destination: LogDestin let filter = EnvFilter::new(&level) .add_directive("h2=off".parse().unwrap()) .add_directive("tower::buffer=off".parse().unwrap()) - .add_directive("hyper_util=off".parse().unwrap()); + .add_directive("hyper_util=off".parse().unwrap()) + .add_directive("opentelemetry=off".parse().unwrap()); let subscriber = tracing_subscriber::registry() .with(create_fmt_layer(&level, format, destination)) diff --git a/crates/tower-uv/Cargo.toml b/crates/tower-uv/Cargo.toml index bd6f1381..fc41a6f0 100644 --- a/crates/tower-uv/Cargo.toml +++ b/crates/tower-uv/Cargo.toml @@ -15,6 +15,7 @@ futures-lite = { workspace = true } hex = { workspace = true } regex = { workspace = true } reqwest = { workspace = true } +rustls = { workspace = true } seahash = { workspace = true } tokio = { workspace = true } tokio-tar = { workspace = true } diff --git a/crates/tower-uv/src/install.rs b/crates/tower-uv/src/install.rs index 3f0c7147..e8a5820f 100644 --- a/crates/tower-uv/src/install.rs +++ b/crates/tower-uv/src/install.rs @@ -211,6 +211,8 @@ async fn download_uv_archive(path: &PathBuf, archive: String) -> Result bool { - cwd.join("requirements.txt").exists() + /// Builds a `uv pip install` command with our standard stdio/color setup. + /// Callers append source args (e.g. `-r requirements.txt` or `.`), any extra + /// packages, and `envs` before spawning. + fn pip_install(&self, cwd: &Path) -> Command { + let mut cmd = Command::new(&self.uv_path); + cmd.kill_on_drop(true) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .current_dir(cwd) + .arg("--color") + .arg("never") + .arg("pip") + .arg("install"); + cmd } - /// Re-runs the `requirements.txt` install with a `setuptools<82` pin appended. + /// Re-runs the install with a `setuptools<82` pin appended. /// /// setuptools 82 removed `pkg_resources`, but many legacy packages still import /// it without declaring the dependency. Pinning `setuptools<82` keeps it /// available. Some modern packages (e.g. dlt's transitive graph pinning /// `setuptools==82.0.1`) make this pin unsatisfiable, so it isn't applied up - /// front — callers should fall back to this only after a plain `sync()` - /// fails for a project using `requirements.txt`. + /// front — callers should fall back to this only after a plain `sync()` fails. + /// + /// Drops out of `uv sync` (which can't accept a CLI constraint) into `uv pip + /// install`, which can. The project source is `.` for a pyproject project or + /// `-r requirements.txt` otherwise. /// /// https://github.com/pypa/setuptools/issues/5174 pub async fn sync_with_legacy_setuptools_pin( @@ -387,44 +413,22 @@ impl Uv { cwd: &PathBuf, env_vars: &HashMap, ) -> Result { - if !cwd.join("requirements.txt").exists() { - return Err(Error::MissingPyprojectToml); - } - debug!( - "Retrying UV ({:?}) sync with setuptools<82 pin in {:?}", + "Retrying UV ({:?}) install with setuptools<82 pin in {:?}", &self.uv_path, cwd ); - self.spawn_requirements_install(cwd, env_vars, true).await - } - - async fn spawn_requirements_install( - &self, - cwd: &PathBuf, - env_vars: &HashMap, - pin_legacy_setuptools: bool, - ) -> Result { - let req_path = cwd.join("requirements.txt"); - - let mut cmd = Command::new(&self.uv_path); - cmd.kill_on_drop(true) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .current_dir(cwd) - .arg("--color") - .arg("never") - .arg("pip") - .arg("install") - .arg("-r") - .arg(&req_path); + let mut cmd = self.pip_install(cwd); - if pin_legacy_setuptools { - cmd.arg("setuptools<82"); + if cwd.join("pyproject.toml").exists() { + cmd.arg("."); + } else if cwd.join("requirements.txt").exists() { + cmd.arg("-r").arg(cwd.join("requirements.txt")); + } else { + return Err(Error::MissingPyprojectToml); } - cmd.envs(env_vars); + cmd.arg("setuptools<82").envs(env_vars); #[cfg(unix)] { diff --git a/crates/tower-uv/tests/sync_test.rs b/crates/tower-uv/tests/sync_test.rs index b2cc8387..df692164 100644 --- a/crates/tower-uv/tests/sync_test.rs +++ b/crates/tower-uv/tests/sync_test.rs @@ -116,7 +116,7 @@ async fn sync_with_legacy_setuptools_pin_fails_when_user_requires_modern_setupto } #[tokio::test] -async fn sync_with_legacy_setuptools_pin_errors_without_requirements_txt() { +async fn sync_with_legacy_setuptools_pin_errors_without_project_files() { let tmp = TempDir::new().expect("tempdir"); let cwd = tmp.path().to_path_buf(); @@ -125,6 +125,58 @@ async fn sync_with_legacy_setuptools_pin_errors_without_requirements_txt() { let result = uv.sync_with_legacy_setuptools_pin(&cwd, &env_vars).await; assert!( matches!(result, Err(tower_uv::Error::MissingPyprojectToml)), - "fallback should refuse to run without a requirements.txt" + "fallback should refuse to run without pyproject.toml or requirements.txt" + ); +} + +#[tokio::test] +async fn sync_with_legacy_setuptools_pin_fails_for_pyproject_requiring_modern_setuptools() { + let tmp = TempDir::new().expect("tempdir"); + let cwd = tmp.path().to_path_buf(); + + // Mirrors the requirements.txt counterpart: when the project pins + // setuptools>=82, the pin must conflict — proving it's actually applied. + tokio::fs::write( + cwd.join("pyproject.toml"), + "[project]\nname = \"test-app\"\nversion = \"0.0.1\"\nrequires-python = \">=3.10\"\ndependencies = [\"setuptools>=82\"]\n", + ) + .await + .expect("write pyproject.toml"); + + let uv = make_uv_with_venv(&cwd).await; + let env_vars: HashMap = HashMap::new(); + let child = uv + .sync_with_legacy_setuptools_pin(&cwd, &env_vars) + .await + .expect("retry spawn failed"); + let code = wait(child).await; + assert_ne!( + code, 0, + "sync_with_legacy_setuptools_pin should fail when the pyproject project requires setuptools>=82" + ); +} + +#[tokio::test] +async fn sync_with_legacy_setuptools_pin_installs_for_pyproject() { + let tmp = TempDir::new().expect("tempdir"); + let cwd = tmp.path().to_path_buf(); + + tokio::fs::write( + cwd.join("pyproject.toml"), + "[project]\nname = \"test-app\"\nversion = \"0.0.1\"\nrequires-python = \">=3.10\"\ndependencies = [\"six\"]\n", + ) + .await + .expect("write pyproject.toml"); + + let uv = make_uv_with_venv(&cwd).await; + let env_vars: HashMap = HashMap::new(); + let child = uv + .sync_with_legacy_setuptools_pin(&cwd, &env_vars) + .await + .expect("retry spawn failed"); + let code = wait(child).await; + assert_eq!( + code, 0, + "sync_with_legacy_setuptools_pin should succeed for a pyproject project" ); } diff --git a/pyproject.toml b/pyproject.toml index d67129a4..a6eb82fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "tower" -version = "0.3.61" +version = "0.3.62" description = "Tower CLI and runtime environment for Tower." authors = [{ name = "Tower Computing Inc.", email = "brad@tower.dev" }] readme = "README.md" diff --git a/scripts/rust-client-templates/Cargo.mustache b/scripts/rust-client-templates/Cargo.mustache index 6ef32880..46f21f1a 100644 --- a/scripts/rust-client-templates/Cargo.mustache +++ b/scripts/rust-client-templates/Cargo.mustache @@ -44,7 +44,7 @@ reqwest-middleware = { version = "^0.4", features = ["json", "blocking", "multip {{/supportMiddleware}} {{/supportAsync}} {{#supportAsync}} -reqwest = { version = "^0.12", default-features = false, features = ["json", "multipart", "rustls-tls"] } +reqwest = { version = "^0.12", default-features = false, features = ["json", "multipart", "rustls-tls-webpki-roots-no-provider"] } {{#supportMiddleware}} reqwest-middleware = { version = "^0.4", features = ["json", "multipart"] } {{/supportMiddleware}} diff --git a/skills/tower/SKILL.md b/skills/tower/SKILL.md index 5a3a0176..13ca2c05 100644 --- a/skills/tower/SKILL.md +++ b/skills/tower/SKILL.md @@ -151,6 +151,10 @@ Manage the apps in your current Tower account List all apps in your Tower account +**Arguments:** + +- `-e`, `--environment` — Filter apps by environment + #### `tower apps show` Show details for a Tower app and its recent runs @@ -158,6 +162,7 @@ Show details for a Tower app and its recent runs **Arguments:** - `` *(required)* — Name of the app +- `-e`, `--environment` — The environment to resolve the app against #### `tower apps logs` diff --git a/src/tower/_client.py b/src/tower/_client.py index 02124280..9ec118f7 100644 --- a/src/tower/_client.py +++ b/src/tower/_client.py @@ -24,6 +24,7 @@ RunAppParams, RunAppParamsParameters, RunAppResponse, + RunStatus, ) from .tower_api_client.models.error_model import ErrorModel from .tower_api_client.errors import UnexpectedStatus @@ -44,6 +45,33 @@ # API before we just give up entirely. DEFAULT_NUM_TIMEOUT_RETRIES = 5 +# TERMINAL_RUN_STATUSES are the run statuses that indicate that a run has finished, +# regardless of whether it completed successfully or not. +TERMINAL_RUN_STATUSES = [ + RunStatus.EXITED, + RunStatus.CANCELLED, + RunStatus.CRASHED, + RunStatus.ERRORED, +] + +# SUCCESSFUL_RUN_STATUSES are the run statuses that indicate that a run has finished and +# completed successfully. +SUCCESSFUL_RUN_STATUSES = [RunStatus.EXITED] + +# FAILED_RUN_STATUSES are the run statuses that indicate that a run has finished but +# did not complete successfully. +FAILED_RUN_STATUSES = [RunStatus.ERRORED, RunStatus.CANCELLED, RunStatus.CRASHED] + +# AWAITING_RUN_STATUSES are the run statuses that indicate that a run is either currently +# running or is expected to run in the near future. +AWAITING_RUN_STATUSES = [ + RunStatus.PENDING, + RunStatus.SCHEDULED, + RunStatus.RUNNING, + RunStatus.STARTING, + RunStatus.RETRYING, +] + def run_app( name: str, @@ -279,7 +307,7 @@ def _is_failed_run(run: Run) -> bool: Returns: bool: True if the run has failed, False otherwise. """ - return run.status in ["crashed", "cancelled", "errored"] + return run.status in FAILED_RUN_STATUSES def _is_successful_run(run: Run) -> bool: @@ -292,7 +320,7 @@ def _is_successful_run(run: Run) -> bool: Returns: bool: True if the run was successful, False otherwise. """ - return run.status in ["exited"] + return run.status in SUCCESSFUL_RUN_STATUSES def _is_run_awaiting_completion(run: Run) -> bool: @@ -305,7 +333,7 @@ def _is_run_awaiting_completion(run: Run) -> bool: Returns: bool: True if the run is awaiting run or currently running, False otherwise. """ - return run.status in ["pending", "scheduled", "running"] + return run.status in AWAITING_RUN_STATUSES def _env_client( diff --git a/src/tower/tower_api_client/api/default/create_password_reset.py b/src/tower/tower_api_client/api/default/create_password_reset.py deleted file mode 100644 index d109aa3a..00000000 --- a/src/tower/tower_api_client/api/default/create_password_reset.py +++ /dev/null @@ -1,171 +0,0 @@ -from http import HTTPStatus -from typing import Any - -import httpx - -from ...client import AuthenticatedClient, Client -from ...models.create_password_reset_params import CreatePasswordResetParams -from ...models.create_password_reset_response import CreatePasswordResetResponse -from ...models.error_model import ErrorModel -from ...types import Response - - -def _get_kwargs( - *, - body: CreatePasswordResetParams, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/accounts/password-reset", - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> CreatePasswordResetResponse | ErrorModel: - if response.status_code == 200: - response_200 = CreatePasswordResetResponse.from_dict(response.json()) - - return response_200 - - response_default = ErrorModel.from_dict(response.json()) - - return response_default - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[CreatePasswordResetResponse | ErrorModel]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: AuthenticatedClient | Client, - body: CreatePasswordResetParams, -) -> Response[CreatePasswordResetResponse | ErrorModel]: - """Create password reset - - Starts the password reset process for an account. If an email address exists for the account - supplied, you will get a reset password email. - - Args: - body (CreatePasswordResetParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[CreatePasswordResetResponse | ErrorModel] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: AuthenticatedClient | Client, - body: CreatePasswordResetParams, -) -> CreatePasswordResetResponse | ErrorModel | None: - """Create password reset - - Starts the password reset process for an account. If an email address exists for the account - supplied, you will get a reset password email. - - Args: - body (CreatePasswordResetParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - CreatePasswordResetResponse | ErrorModel - """ - - return sync_detailed( - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - *, - client: AuthenticatedClient | Client, - body: CreatePasswordResetParams, -) -> Response[CreatePasswordResetResponse | ErrorModel]: - """Create password reset - - Starts the password reset process for an account. If an email address exists for the account - supplied, you will get a reset password email. - - Args: - body (CreatePasswordResetParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[CreatePasswordResetResponse | ErrorModel] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: AuthenticatedClient | Client, - body: CreatePasswordResetParams, -) -> CreatePasswordResetResponse | ErrorModel | None: - """Create password reset - - Starts the password reset process for an account. If an email address exists for the account - supplied, you will get a reset password email. - - Args: - body (CreatePasswordResetParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - CreatePasswordResetResponse | ErrorModel - """ - - return ( - await asyncio_detailed( - client=client, - body=body, - ) - ).parsed diff --git a/src/tower/tower_api_client/api/default/delete_authenticator.py b/src/tower/tower_api_client/api/default/delete_authenticator.py deleted file mode 100644 index 29997b88..00000000 --- a/src/tower/tower_api_client/api/default/delete_authenticator.py +++ /dev/null @@ -1,167 +0,0 @@ -from http import HTTPStatus -from typing import Any - -import httpx - -from ...client import AuthenticatedClient, Client -from ...models.delete_authenticator_params import DeleteAuthenticatorParams -from ...models.delete_authenticator_response import DeleteAuthenticatorResponse -from ...models.error_model import ErrorModel -from ...types import Response - - -def _get_kwargs( - *, - body: DeleteAuthenticatorParams, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "delete", - "url": "/authenticators", - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> DeleteAuthenticatorResponse | ErrorModel: - if response.status_code == 200: - response_200 = DeleteAuthenticatorResponse.from_dict(response.json()) - - return response_200 - - response_default = ErrorModel.from_dict(response.json()) - - return response_default - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[DeleteAuthenticatorResponse | ErrorModel]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: AuthenticatedClient, - body: DeleteAuthenticatorParams, -) -> Response[DeleteAuthenticatorResponse | ErrorModel]: - """Delete authenticator - - Removes an authenticator from your account so you're no longer required to provide it at login. - - Args: - body (DeleteAuthenticatorParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[DeleteAuthenticatorResponse | ErrorModel] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: AuthenticatedClient, - body: DeleteAuthenticatorParams, -) -> DeleteAuthenticatorResponse | ErrorModel | None: - """Delete authenticator - - Removes an authenticator from your account so you're no longer required to provide it at login. - - Args: - body (DeleteAuthenticatorParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - DeleteAuthenticatorResponse | ErrorModel - """ - - return sync_detailed( - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - *, - client: AuthenticatedClient, - body: DeleteAuthenticatorParams, -) -> Response[DeleteAuthenticatorResponse | ErrorModel]: - """Delete authenticator - - Removes an authenticator from your account so you're no longer required to provide it at login. - - Args: - body (DeleteAuthenticatorParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[DeleteAuthenticatorResponse | ErrorModel] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: AuthenticatedClient, - body: DeleteAuthenticatorParams, -) -> DeleteAuthenticatorResponse | ErrorModel | None: - """Delete authenticator - - Removes an authenticator from your account so you're no longer required to provide it at login. - - Args: - body (DeleteAuthenticatorParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - DeleteAuthenticatorResponse | ErrorModel - """ - - return ( - await asyncio_detailed( - client=client, - body=body, - ) - ).parsed diff --git a/src/tower/tower_api_client/api/default/deploy_app.py b/src/tower/tower_api_client/api/default/deploy_app.py index 902a7b34..3e822ae0 100644 --- a/src/tower/tower_api_client/api/default/deploy_app.py +++ b/src/tower/tower_api_client/api/default/deploy_app.py @@ -16,6 +16,8 @@ def _get_kwargs( name: str, *, body: DeployAppJsonBody | File | Unset = UNSET, + environment: str | Unset = UNSET, + all_environments: bool | Unset = False, x_tower_checksum_sha256: str | Unset = UNSET, content_length: int | Unset = UNSET, ) -> dict[str, Any]: @@ -26,11 +28,20 @@ def _get_kwargs( if not isinstance(content_length, Unset): headers["Content-Length"] = str(content_length) + params: dict[str, Any] = {} + + params["environment"] = environment + + params["all_environments"] = all_environments + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = { "method": "post", "url": "/apps/{name}/deploy".format( name=quote(str(name), safe=""), ), + "params": params, } if isinstance(body, DeployAppJsonBody): @@ -91,6 +102,8 @@ def sync_detailed( *, client: AuthenticatedClient, body: DeployAppJsonBody | File | Unset = UNSET, + environment: str | Unset = UNSET, + all_environments: bool | Unset = False, x_tower_checksum_sha256: str | Unset = UNSET, content_length: int | Unset = UNSET, ) -> Response[DeployAppResponse | ErrorModel]: @@ -101,6 +114,9 @@ def sync_detailed( Args: name (str): The name of the app to deploy. + environment (str | Unset): The environment to deploy to. + all_environments (bool | Unset): Whether to deploy to all environments for this app. If + true, the 'environment' query parameter is ignored. Default: False. x_tower_checksum_sha256 (str | Unset): The SHA256 hash of the content, used to verify integrity. content_length (int | Unset): Size of the uploaded bundle in bytes. @@ -120,6 +136,8 @@ def sync_detailed( kwargs = _get_kwargs( name=name, body=body, + environment=environment, + all_environments=all_environments, x_tower_checksum_sha256=x_tower_checksum_sha256, content_length=content_length, ) @@ -136,6 +154,8 @@ def sync( *, client: AuthenticatedClient, body: DeployAppJsonBody | File | Unset = UNSET, + environment: str | Unset = UNSET, + all_environments: bool | Unset = False, x_tower_checksum_sha256: str | Unset = UNSET, content_length: int | Unset = UNSET, ) -> DeployAppResponse | ErrorModel | None: @@ -146,6 +166,9 @@ def sync( Args: name (str): The name of the app to deploy. + environment (str | Unset): The environment to deploy to. + all_environments (bool | Unset): Whether to deploy to all environments for this app. If + true, the 'environment' query parameter is ignored. Default: False. x_tower_checksum_sha256 (str | Unset): The SHA256 hash of the content, used to verify integrity. content_length (int | Unset): Size of the uploaded bundle in bytes. @@ -166,6 +189,8 @@ def sync( name=name, client=client, body=body, + environment=environment, + all_environments=all_environments, x_tower_checksum_sha256=x_tower_checksum_sha256, content_length=content_length, ).parsed @@ -176,6 +201,8 @@ async def asyncio_detailed( *, client: AuthenticatedClient, body: DeployAppJsonBody | File | Unset = UNSET, + environment: str | Unset = UNSET, + all_environments: bool | Unset = False, x_tower_checksum_sha256: str | Unset = UNSET, content_length: int | Unset = UNSET, ) -> Response[DeployAppResponse | ErrorModel]: @@ -186,6 +213,9 @@ async def asyncio_detailed( Args: name (str): The name of the app to deploy. + environment (str | Unset): The environment to deploy to. + all_environments (bool | Unset): Whether to deploy to all environments for this app. If + true, the 'environment' query parameter is ignored. Default: False. x_tower_checksum_sha256 (str | Unset): The SHA256 hash of the content, used to verify integrity. content_length (int | Unset): Size of the uploaded bundle in bytes. @@ -205,6 +235,8 @@ async def asyncio_detailed( kwargs = _get_kwargs( name=name, body=body, + environment=environment, + all_environments=all_environments, x_tower_checksum_sha256=x_tower_checksum_sha256, content_length=content_length, ) @@ -219,6 +251,8 @@ async def asyncio( *, client: AuthenticatedClient, body: DeployAppJsonBody | File | Unset = UNSET, + environment: str | Unset = UNSET, + all_environments: bool | Unset = False, x_tower_checksum_sha256: str | Unset = UNSET, content_length: int | Unset = UNSET, ) -> DeployAppResponse | ErrorModel | None: @@ -229,6 +263,9 @@ async def asyncio( Args: name (str): The name of the app to deploy. + environment (str | Unset): The environment to deploy to. + all_environments (bool | Unset): Whether to deploy to all environments for this app. If + true, the 'environment' query parameter is ignored. Default: False. x_tower_checksum_sha256 (str | Unset): The SHA256 hash of the content, used to verify integrity. content_length (int | Unset): Size of the uploaded bundle in bytes. @@ -250,6 +287,8 @@ async def asyncio( name=name, client=client, body=body, + environment=environment, + all_environments=all_environments, x_tower_checksum_sha256=x_tower_checksum_sha256, content_length=content_length, ) diff --git a/src/tower/tower_api_client/api/default/describe_app.py b/src/tower/tower_api_client/api/default/describe_app.py index c9561e96..e5b4605d 100644 --- a/src/tower/tower_api_client/api/default/describe_app.py +++ b/src/tower/tower_api_client/api/default/describe_app.py @@ -18,6 +18,7 @@ def _get_kwargs( start_at: datetime.datetime | Unset = UNSET, end_at: datetime.datetime | Unset = UNSET, timezone: str | Unset = "UTC", + environment: str | Unset = "default", ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -35,6 +36,8 @@ def _get_kwargs( params["timezone"] = timezone + params["environment"] = environment + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { @@ -80,6 +83,7 @@ def sync_detailed( start_at: datetime.datetime | Unset = UNSET, end_at: datetime.datetime | Unset = UNSET, timezone: str | Unset = "UTC", + environment: str | Unset = "default", ) -> Response[DescribeAppResponse | ErrorModel]: """Describe app @@ -94,6 +98,8 @@ def sync_detailed( (inclusive). Provide timestamps in ISO-8601 format. timezone (str | Unset): Timezone for the statistics (e.g., 'Europe/Berlin'). Defaults to UTC. Default: 'UTC'. + environment (str | Unset): The environment to resolve the app version against. Defaults to + 'default'. Default: 'default'. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -109,6 +115,7 @@ def sync_detailed( start_at=start_at, end_at=end_at, timezone=timezone, + environment=environment, ) response = client.get_httpx_client().request( @@ -126,6 +133,7 @@ def sync( start_at: datetime.datetime | Unset = UNSET, end_at: datetime.datetime | Unset = UNSET, timezone: str | Unset = "UTC", + environment: str | Unset = "default", ) -> DescribeAppResponse | ErrorModel | None: """Describe app @@ -140,6 +148,8 @@ def sync( (inclusive). Provide timestamps in ISO-8601 format. timezone (str | Unset): Timezone for the statistics (e.g., 'Europe/Berlin'). Defaults to UTC. Default: 'UTC'. + environment (str | Unset): The environment to resolve the app version against. Defaults to + 'default'. Default: 'default'. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -156,6 +166,7 @@ def sync( start_at=start_at, end_at=end_at, timezone=timezone, + environment=environment, ).parsed @@ -167,6 +178,7 @@ async def asyncio_detailed( start_at: datetime.datetime | Unset = UNSET, end_at: datetime.datetime | Unset = UNSET, timezone: str | Unset = "UTC", + environment: str | Unset = "default", ) -> Response[DescribeAppResponse | ErrorModel]: """Describe app @@ -181,6 +193,8 @@ async def asyncio_detailed( (inclusive). Provide timestamps in ISO-8601 format. timezone (str | Unset): Timezone for the statistics (e.g., 'Europe/Berlin'). Defaults to UTC. Default: 'UTC'. + environment (str | Unset): The environment to resolve the app version against. Defaults to + 'default'. Default: 'default'. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -196,6 +210,7 @@ async def asyncio_detailed( start_at=start_at, end_at=end_at, timezone=timezone, + environment=environment, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -211,6 +226,7 @@ async def asyncio( start_at: datetime.datetime | Unset = UNSET, end_at: datetime.datetime | Unset = UNSET, timezone: str | Unset = "UTC", + environment: str | Unset = "default", ) -> DescribeAppResponse | ErrorModel | None: """Describe app @@ -225,6 +241,8 @@ async def asyncio( (inclusive). Provide timestamps in ISO-8601 format. timezone (str | Unset): Timezone for the statistics (e.g., 'Europe/Berlin'). Defaults to UTC. Default: 'UTC'. + environment (str | Unset): The environment to resolve the app version against. Defaults to + 'default'. Default: 'default'. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -242,5 +260,6 @@ async def asyncio( start_at=start_at, end_at=end_at, timezone=timezone, + environment=environment, ) ).parsed diff --git a/src/tower/tower_api_client/api/default/describe_organization_usage.py b/src/tower/tower_api_client/api/default/describe_organization_usage.py index 9cfc44c2..ca1759a5 100644 --- a/src/tower/tower_api_client/api/default/describe_organization_usage.py +++ b/src/tower/tower_api_client/api/default/describe_organization_usage.py @@ -48,7 +48,7 @@ def sync_detailed( ) -> Response[ErrorModel | OrganizationUsage]: """Describe organization usage - Describe usage statistics for the user's organization. + Describe usage statistics for the user's organization for the current billing cycle. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -73,7 +73,7 @@ def sync( ) -> ErrorModel | OrganizationUsage | None: """Describe organization usage - Describe usage statistics for the user's organization. + Describe usage statistics for the user's organization for the current billing cycle. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -94,7 +94,7 @@ async def asyncio_detailed( ) -> Response[ErrorModel | OrganizationUsage]: """Describe organization usage - Describe usage statistics for the user's organization. + Describe usage statistics for the user's organization for the current billing cycle. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -117,7 +117,7 @@ async def asyncio( ) -> ErrorModel | OrganizationUsage | None: """Describe organization usage - Describe usage statistics for the user's organization. + Describe usage statistics for the user's organization for the current billing cycle. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/src/tower/tower_api_client/api/default/generate_authenticator.py b/src/tower/tower_api_client/api/default/generate_authenticator.py deleted file mode 100644 index a2f21bb8..00000000 --- a/src/tower/tower_api_client/api/default/generate_authenticator.py +++ /dev/null @@ -1,134 +0,0 @@ -from http import HTTPStatus -from typing import Any - -import httpx - -from ...client import AuthenticatedClient, Client -from ...models.error_model import ErrorModel -from ...models.generate_authenticator_response import GenerateAuthenticatorResponse -from ...types import Response - - -def _get_kwargs() -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/authenticators/generate", - } - - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorModel | GenerateAuthenticatorResponse: - if response.status_code == 200: - response_200 = GenerateAuthenticatorResponse.from_dict(response.json()) - - return response_200 - - response_default = ErrorModel.from_dict(response.json()) - - return response_default - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorModel | GenerateAuthenticatorResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: AuthenticatedClient, -) -> Response[ErrorModel | GenerateAuthenticatorResponse]: - """Generate authenticator - - Generates a new authenticator for the user. This is used to set up two-factor authentication. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorModel | GenerateAuthenticatorResponse] - """ - - kwargs = _get_kwargs() - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: AuthenticatedClient, -) -> ErrorModel | GenerateAuthenticatorResponse | None: - """Generate authenticator - - Generates a new authenticator for the user. This is used to set up two-factor authentication. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorModel | GenerateAuthenticatorResponse - """ - - return sync_detailed( - client=client, - ).parsed - - -async def asyncio_detailed( - *, - client: AuthenticatedClient, -) -> Response[ErrorModel | GenerateAuthenticatorResponse]: - """Generate authenticator - - Generates a new authenticator for the user. This is used to set up two-factor authentication. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorModel | GenerateAuthenticatorResponse] - """ - - kwargs = _get_kwargs() - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: AuthenticatedClient, -) -> ErrorModel | GenerateAuthenticatorResponse | None: - """Generate authenticator - - Generates a new authenticator for the user. This is used to set up two-factor authentication. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorModel | GenerateAuthenticatorResponse - """ - - return ( - await asyncio_detailed( - client=client, - ) - ).parsed diff --git a/src/tower/tower_api_client/api/default/list_authenticators.py b/src/tower/tower_api_client/api/default/generate_organization_usage_time_series.py similarity index 64% rename from src/tower/tower_api_client/api/default/list_authenticators.py rename to src/tower/tower_api_client/api/default/generate_organization_usage_time_series.py index 9029a659..c866ff4c 100644 --- a/src/tower/tower_api_client/api/default/list_authenticators.py +++ b/src/tower/tower_api_client/api/default/generate_organization_usage_time_series.py @@ -5,14 +5,16 @@ from ...client import AuthenticatedClient, Client from ...models.error_model import ErrorModel -from ...models.list_authenticators_response import ListAuthenticatorsResponse +from ...models.generate_organization_usage_time_series_response import ( + GenerateOrganizationUsageTimeSeriesResponse, +) from ...types import Response def _get_kwargs() -> dict[str, Any]: _kwargs: dict[str, Any] = { "method": "get", - "url": "/authenticators", + "url": "/usage/time-series", } return _kwargs @@ -20,9 +22,11 @@ def _get_kwargs() -> dict[str, Any]: def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorModel | ListAuthenticatorsResponse: +) -> ErrorModel | GenerateOrganizationUsageTimeSeriesResponse: if response.status_code == 200: - response_200 = ListAuthenticatorsResponse.from_dict(response.json()) + response_200 = GenerateOrganizationUsageTimeSeriesResponse.from_dict( + response.json() + ) return response_200 @@ -33,7 +37,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorModel | ListAuthenticatorsResponse]: +) -> Response[ErrorModel | GenerateOrganizationUsageTimeSeriesResponse]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -45,17 +49,17 @@ def _build_response( def sync_detailed( *, client: AuthenticatedClient, -) -> Response[ErrorModel | ListAuthenticatorsResponse]: - """List authenticators +) -> Response[ErrorModel | GenerateOrganizationUsageTimeSeriesResponse]: + """Get organization usage as time series - Enumerates the authenticators associated with the current users' account + Get the current billing cycle usage as a time series. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[ErrorModel | ListAuthenticatorsResponse] + Response[ErrorModel | GenerateOrganizationUsageTimeSeriesResponse] """ kwargs = _get_kwargs() @@ -70,17 +74,17 @@ def sync_detailed( def sync( *, client: AuthenticatedClient, -) -> ErrorModel | ListAuthenticatorsResponse | None: - """List authenticators +) -> ErrorModel | GenerateOrganizationUsageTimeSeriesResponse | None: + """Get organization usage as time series - Enumerates the authenticators associated with the current users' account + Get the current billing cycle usage as a time series. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - ErrorModel | ListAuthenticatorsResponse + ErrorModel | GenerateOrganizationUsageTimeSeriesResponse """ return sync_detailed( @@ -91,17 +95,17 @@ def sync( async def asyncio_detailed( *, client: AuthenticatedClient, -) -> Response[ErrorModel | ListAuthenticatorsResponse]: - """List authenticators +) -> Response[ErrorModel | GenerateOrganizationUsageTimeSeriesResponse]: + """Get organization usage as time series - Enumerates the authenticators associated with the current users' account + Get the current billing cycle usage as a time series. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[ErrorModel | ListAuthenticatorsResponse] + Response[ErrorModel | GenerateOrganizationUsageTimeSeriesResponse] """ kwargs = _get_kwargs() @@ -114,17 +118,17 @@ async def asyncio_detailed( async def asyncio( *, client: AuthenticatedClient, -) -> ErrorModel | ListAuthenticatorsResponse | None: - """List authenticators +) -> ErrorModel | GenerateOrganizationUsageTimeSeriesResponse | None: + """Get organization usage as time series - Enumerates the authenticators associated with the current users' account + Get the current billing cycle usage as a time series. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - ErrorModel | ListAuthenticatorsResponse + ErrorModel | GenerateOrganizationUsageTimeSeriesResponse """ return ( diff --git a/src/tower/tower_api_client/api/default/resend_email_verification.py b/src/tower/tower_api_client/api/default/resend_email_verification.py deleted file mode 100644 index 3740d15e..00000000 --- a/src/tower/tower_api_client/api/default/resend_email_verification.py +++ /dev/null @@ -1,136 +0,0 @@ -from http import HTTPStatus -from typing import Any, cast - -import httpx - -from ...client import AuthenticatedClient, Client -from ...models.error_model import ErrorModel -from ...types import Response - - -def _get_kwargs() -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/user/resend-verification", - } - - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Any | ErrorModel: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - - response_default = ErrorModel.from_dict(response.json()) - - return response_default - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Any | ErrorModel]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: AuthenticatedClient, -) -> Response[Any | ErrorModel]: - """Resent email verification - - If a user doesn't have a verified email address, this API endpoint will send a new confirmation - email to them - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any | ErrorModel] - """ - - kwargs = _get_kwargs() - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: AuthenticatedClient, -) -> Any | ErrorModel | None: - """Resent email verification - - If a user doesn't have a verified email address, this API endpoint will send a new confirmation - email to them - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Any | ErrorModel - """ - - return sync_detailed( - client=client, - ).parsed - - -async def asyncio_detailed( - *, - client: AuthenticatedClient, -) -> Response[Any | ErrorModel]: - """Resent email verification - - If a user doesn't have a verified email address, this API endpoint will send a new confirmation - email to them - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any | ErrorModel] - """ - - kwargs = _get_kwargs() - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: AuthenticatedClient, -) -> Any | ErrorModel | None: - """Resent email verification - - If a user doesn't have a verified email address, this API endpoint will send a new confirmation - email to them - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Any | ErrorModel - """ - - return ( - await asyncio_detailed( - client=client, - ) - ).parsed diff --git a/src/tower/tower_api_client/api/default/create_authenticator.py b/src/tower/tower_api_client/api/default/update_app_environment.py similarity index 51% rename from src/tower/tower_api_client/api/default/create_authenticator.py rename to src/tower/tower_api_client/api/default/update_app_environment.py index 25d4e6fd..1c3d2ac3 100644 --- a/src/tower/tower_api_client/api/default/create_authenticator.py +++ b/src/tower/tower_api_client/api/default/update_app_environment.py @@ -1,24 +1,30 @@ from http import HTTPStatus from typing import Any +from urllib.parse import quote import httpx from ...client import AuthenticatedClient, Client -from ...models.create_authenticator_params import CreateAuthenticatorParams -from ...models.create_authenticator_response import CreateAuthenticatorResponse from ...models.error_model import ErrorModel +from ...models.update_app_environment_params import UpdateAppEnvironmentParams +from ...models.update_app_environment_response import UpdateAppEnvironmentResponse from ...types import Response def _get_kwargs( + name: str, + environment: str, *, - body: CreateAuthenticatorParams, + body: UpdateAppEnvironmentParams, ) -> dict[str, Any]: headers: dict[str, Any] = {} _kwargs: dict[str, Any] = { - "method": "post", - "url": "/authenticators", + "method": "put", + "url": "/apps/{name}/environments/{environment}".format( + name=quote(str(name), safe=""), + environment=quote(str(environment), safe=""), + ), } _kwargs["json"] = body.to_dict() @@ -31,9 +37,9 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> CreateAuthenticatorResponse | ErrorModel: +) -> ErrorModel | UpdateAppEnvironmentResponse: if response.status_code == 200: - response_200 = CreateAuthenticatorResponse.from_dict(response.json()) + response_200 = UpdateAppEnvironmentResponse.from_dict(response.json()) return response_200 @@ -44,7 +50,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[CreateAuthenticatorResponse | ErrorModel]: +) -> Response[ErrorModel | UpdateAppEnvironmentResponse]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -54,27 +60,32 @@ def _build_response( def sync_detailed( + name: str, + environment: str, *, client: AuthenticatedClient, - body: CreateAuthenticatorParams, -) -> Response[CreateAuthenticatorResponse | ErrorModel]: - """Create authenticator + body: UpdateAppEnvironmentParams, +) -> Response[ErrorModel | UpdateAppEnvironmentResponse]: + """Update app environment - Associates an authenticator with your account, where the authenticator is identified by the URL with - an otpauth URI scheme. + Update the configuration of an app in a specific environment, such as which version is deployed. Args: - body (CreateAuthenticatorParams): + name (str): The name of the app. + environment (str): The name of the environment. + body (UpdateAppEnvironmentParams): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[CreateAuthenticatorResponse | ErrorModel] + Response[ErrorModel | UpdateAppEnvironmentResponse] """ kwargs = _get_kwargs( + name=name, + environment=environment, body=body, ) @@ -86,54 +97,64 @@ def sync_detailed( def sync( + name: str, + environment: str, *, client: AuthenticatedClient, - body: CreateAuthenticatorParams, -) -> CreateAuthenticatorResponse | ErrorModel | None: - """Create authenticator + body: UpdateAppEnvironmentParams, +) -> ErrorModel | UpdateAppEnvironmentResponse | None: + """Update app environment - Associates an authenticator with your account, where the authenticator is identified by the URL with - an otpauth URI scheme. + Update the configuration of an app in a specific environment, such as which version is deployed. Args: - body (CreateAuthenticatorParams): + name (str): The name of the app. + environment (str): The name of the environment. + body (UpdateAppEnvironmentParams): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - CreateAuthenticatorResponse | ErrorModel + ErrorModel | UpdateAppEnvironmentResponse """ return sync_detailed( + name=name, + environment=environment, client=client, body=body, ).parsed async def asyncio_detailed( + name: str, + environment: str, *, client: AuthenticatedClient, - body: CreateAuthenticatorParams, -) -> Response[CreateAuthenticatorResponse | ErrorModel]: - """Create authenticator + body: UpdateAppEnvironmentParams, +) -> Response[ErrorModel | UpdateAppEnvironmentResponse]: + """Update app environment - Associates an authenticator with your account, where the authenticator is identified by the URL with - an otpauth URI scheme. + Update the configuration of an app in a specific environment, such as which version is deployed. Args: - body (CreateAuthenticatorParams): + name (str): The name of the app. + environment (str): The name of the environment. + body (UpdateAppEnvironmentParams): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[CreateAuthenticatorResponse | ErrorModel] + Response[ErrorModel | UpdateAppEnvironmentResponse] """ kwargs = _get_kwargs( + name=name, + environment=environment, body=body, ) @@ -143,28 +164,33 @@ async def asyncio_detailed( async def asyncio( + name: str, + environment: str, *, client: AuthenticatedClient, - body: CreateAuthenticatorParams, -) -> CreateAuthenticatorResponse | ErrorModel | None: - """Create authenticator + body: UpdateAppEnvironmentParams, +) -> ErrorModel | UpdateAppEnvironmentResponse | None: + """Update app environment - Associates an authenticator with your account, where the authenticator is identified by the URL with - an otpauth URI scheme. + Update the configuration of an app in a specific environment, such as which version is deployed. Args: - body (CreateAuthenticatorParams): + name (str): The name of the app. + environment (str): The name of the environment. + body (UpdateAppEnvironmentParams): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - CreateAuthenticatorResponse | ErrorModel + ErrorModel | UpdateAppEnvironmentResponse """ return ( await asyncio_detailed( + name=name, + environment=environment, client=client, body=body, ) diff --git a/src/tower/tower_api_client/api/default/update_password_reset.py b/src/tower/tower_api_client/api/default/update_password_reset.py deleted file mode 100644 index 33097d74..00000000 --- a/src/tower/tower_api_client/api/default/update_password_reset.py +++ /dev/null @@ -1,183 +0,0 @@ -from http import HTTPStatus -from typing import Any -from urllib.parse import quote - -import httpx - -from ...client import AuthenticatedClient, Client -from ...models.error_model import ErrorModel -from ...models.update_password_reset_params import UpdatePasswordResetParams -from ...models.update_password_reset_response import UpdatePasswordResetResponse -from ...types import Response - - -def _get_kwargs( - code: str, - *, - body: UpdatePasswordResetParams, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/accounts/password-reset/{code}".format( - code=quote(str(code), safe=""), - ), - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorModel | UpdatePasswordResetResponse: - if response.status_code == 200: - response_200 = UpdatePasswordResetResponse.from_dict(response.json()) - - return response_200 - - response_default = ErrorModel.from_dict(response.json()) - - return response_default - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorModel | UpdatePasswordResetResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - code: str, - *, - client: AuthenticatedClient | Client, - body: UpdatePasswordResetParams, -) -> Response[ErrorModel | UpdatePasswordResetResponse]: - """Update password reset - - Updates the password reset code with the new password - - Args: - code (str): The password reset code that was sent to you - body (UpdatePasswordResetParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorModel | UpdatePasswordResetResponse] - """ - - kwargs = _get_kwargs( - code=code, - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - code: str, - *, - client: AuthenticatedClient | Client, - body: UpdatePasswordResetParams, -) -> ErrorModel | UpdatePasswordResetResponse | None: - """Update password reset - - Updates the password reset code with the new password - - Args: - code (str): The password reset code that was sent to you - body (UpdatePasswordResetParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorModel | UpdatePasswordResetResponse - """ - - return sync_detailed( - code=code, - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - code: str, - *, - client: AuthenticatedClient | Client, - body: UpdatePasswordResetParams, -) -> Response[ErrorModel | UpdatePasswordResetResponse]: - """Update password reset - - Updates the password reset code with the new password - - Args: - code (str): The password reset code that was sent to you - body (UpdatePasswordResetParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorModel | UpdatePasswordResetResponse] - """ - - kwargs = _get_kwargs( - code=code, - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - code: str, - *, - client: AuthenticatedClient | Client, - body: UpdatePasswordResetParams, -) -> ErrorModel | UpdatePasswordResetResponse | None: - """Update password reset - - Updates the password reset code with the new password - - Args: - code (str): The password reset code that was sent to you - body (UpdatePasswordResetParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorModel | UpdatePasswordResetResponse - """ - - return ( - await asyncio_detailed( - code=code, - client=client, - body=body, - ) - ).parsed diff --git a/src/tower/tower_api_client/api/default/verify_email.py b/src/tower/tower_api_client/api/default/verify_email.py deleted file mode 100644 index 7a797a8e..00000000 --- a/src/tower/tower_api_client/api/default/verify_email.py +++ /dev/null @@ -1,171 +0,0 @@ -from http import HTTPStatus -from typing import Any - -import httpx - -from ...client import AuthenticatedClient, Client -from ...models.error_model import ErrorModel -from ...models.verify_email_params import VerifyEmailParams -from ...models.verify_email_response import VerifyEmailResponse -from ...types import Response - - -def _get_kwargs( - *, - body: VerifyEmailParams, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/user/verify", - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorModel | VerifyEmailResponse: - if response.status_code == 200: - response_200 = VerifyEmailResponse.from_dict(response.json()) - - return response_200 - - response_default = ErrorModel.from_dict(response.json()) - - return response_default - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorModel | VerifyEmailResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: AuthenticatedClient, - body: VerifyEmailParams, -) -> Response[ErrorModel | VerifyEmailResponse]: - """Verify email - - If the user hasn't verified their email address, this API endpoint allows them to send a - confirmation token they received via email to indeed verify they can receive emails. - - Args: - body (VerifyEmailParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorModel | VerifyEmailResponse] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: AuthenticatedClient, - body: VerifyEmailParams, -) -> ErrorModel | VerifyEmailResponse | None: - """Verify email - - If the user hasn't verified their email address, this API endpoint allows them to send a - confirmation token they received via email to indeed verify they can receive emails. - - Args: - body (VerifyEmailParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorModel | VerifyEmailResponse - """ - - return sync_detailed( - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - *, - client: AuthenticatedClient, - body: VerifyEmailParams, -) -> Response[ErrorModel | VerifyEmailResponse]: - """Verify email - - If the user hasn't verified their email address, this API endpoint allows them to send a - confirmation token they received via email to indeed verify they can receive emails. - - Args: - body (VerifyEmailParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[ErrorModel | VerifyEmailResponse] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: AuthenticatedClient, - body: VerifyEmailParams, -) -> ErrorModel | VerifyEmailResponse | None: - """Verify email - - If the user hasn't verified their email address, this API endpoint allows them to send a - confirmation token they received via email to indeed verify they can receive emails. - - Args: - body (VerifyEmailParams): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - ErrorModel | VerifyEmailResponse - """ - - return ( - await asyncio_detailed( - client=client, - body=body, - ) - ).parsed diff --git a/src/tower/tower_api_client/models/__init__.py b/src/tower/tower_api_client/models/__init__.py index ae9cfab0..c3cdbb98 100644 --- a/src/tower/tower_api_client/models/__init__.py +++ b/src/tower/tower_api_client/models/__init__.py @@ -26,8 +26,6 @@ from .create_api_key_response import CreateAPIKeyResponse from .create_app_params import CreateAppParams from .create_app_response import CreateAppResponse -from .create_authenticator_params import CreateAuthenticatorParams -from .create_authenticator_response import CreateAuthenticatorResponse from .create_catalog_params import CreateCatalogParams from .create_catalog_params_type import CreateCatalogParamsType from .create_catalog_response import CreateCatalogResponse @@ -36,8 +34,6 @@ from .create_environment_response import CreateEnvironmentResponse from .create_guest_params import CreateGuestParams from .create_guest_response import CreateGuestResponse -from .create_password_reset_params import CreatePasswordResetParams -from .create_password_reset_response import CreatePasswordResetResponse from .create_sandbox_secrets_params import CreateSandboxSecretsParams from .create_sandbox_secrets_response import CreateSandboxSecretsResponse from .create_schedule_params import CreateScheduleParams @@ -55,8 +51,6 @@ from .delete_api_key_params import DeleteAPIKeyParams from .delete_api_key_response import DeleteAPIKeyResponse from .delete_app_response import DeleteAppResponse -from .delete_authenticator_params import DeleteAuthenticatorParams -from .delete_authenticator_response import DeleteAuthenticatorResponse from .delete_catalog_response import DeleteCatalogResponse from .delete_guest_output_body import DeleteGuestOutputBody from .delete_schedule_params import DeleteScheduleParams @@ -102,7 +96,9 @@ from .feature import Feature from .featurebase_identity import FeaturebaseIdentity from .generate_app_statistics_response import GenerateAppStatisticsResponse -from .generate_authenticator_response import GenerateAuthenticatorResponse +from .generate_organization_usage_time_series_response import ( + GenerateOrganizationUsageTimeSeriesResponse, +) from .generate_run_statistics_response import GenerateRunStatisticsResponse from .generate_run_statistics_status_item import GenerateRunStatisticsStatusItem from .generate_runner_credentials_response import GenerateRunnerCredentialsResponse @@ -122,7 +118,6 @@ from .list_apps_filter import ListAppsFilter from .list_apps_response import ListAppsResponse from .list_apps_sort import ListAppsSort -from .list_authenticators_response import ListAuthenticatorsResponse from .list_catalogs_response import ListCatalogsResponse from .list_environments_response import ListEnvironmentsResponse from .list_guests_response import ListGuestsResponse @@ -198,10 +193,11 @@ from .team_membership_role import TeamMembershipRole from .test_webhook_response import TestWebhookResponse from .token import Token -from .unverified_authenticator import UnverifiedAuthenticator from .update_account_params import UpdateAccountParams from .update_account_params_execution_region import UpdateAccountParamsExecutionRegion from .update_account_response import UpdateAccountResponse +from .update_app_environment_params import UpdateAppEnvironmentParams +from .update_app_environment_response import UpdateAppEnvironmentResponse from .update_app_params import UpdateAppParams from .update_app_response import UpdateAppResponse from .update_catalog_params import UpdateCatalogParams @@ -213,8 +209,6 @@ from .update_my_team_invitation_response import UpdateMyTeamInvitationResponse from .update_organization_params import UpdateOrganizationParams from .update_organization_response import UpdateOrganizationResponse -from .update_password_reset_params import UpdatePasswordResetParams -from .update_password_reset_response import UpdatePasswordResetResponse from .update_plan_params import UpdatePlanParams from .update_plan_response import UpdatePlanResponse from .update_schedule_params import UpdateScheduleParams @@ -234,10 +228,9 @@ from .update_webhook_params import UpdateWebhookParams from .update_webhook_response import UpdateWebhookResponse from .usage_limit import UsageLimit +from .usage_metric_time_series_point import UsageMetricTimeSeriesPoint +from .usage_metric_time_series_point_name import UsageMetricTimeSeriesPointName from .user import User -from .verified_authenticator import VerifiedAuthenticator -from .verify_email_params import VerifyEmailParams -from .verify_email_response import VerifyEmailResponse from .webhook import Webhook from .webhook_state import WebhookState @@ -268,8 +261,6 @@ "CreateAPIKeyResponse", "CreateAppParams", "CreateAppResponse", - "CreateAuthenticatorParams", - "CreateAuthenticatorResponse", "CreateCatalogParams", "CreateCatalogParamsType", "CreateCatalogResponse", @@ -278,8 +269,6 @@ "CreateEnvironmentResponse", "CreateGuestParams", "CreateGuestResponse", - "CreatePasswordResetParams", - "CreatePasswordResetResponse", "CreateSandboxSecretsParams", "CreateSandboxSecretsResponse", "CreateScheduleParams", @@ -297,8 +286,6 @@ "DeleteAPIKeyParams", "DeleteAPIKeyResponse", "DeleteAppResponse", - "DeleteAuthenticatorParams", - "DeleteAuthenticatorResponse", "DeleteCatalogResponse", "DeleteGuestOutputBody", "DeleteScheduleParams", @@ -344,7 +331,7 @@ "Feature", "FeaturebaseIdentity", "GenerateAppStatisticsResponse", - "GenerateAuthenticatorResponse", + "GenerateOrganizationUsageTimeSeriesResponse", "GenerateRunnerCredentialsResponse", "GenerateRunStatisticsResponse", "GenerateRunStatisticsStatusItem", @@ -362,7 +349,6 @@ "ListAppsResponse", "ListAppsSort", "ListAppVersionsResponse", - "ListAuthenticatorsResponse", "ListCatalogsResponse", "ListEnvironmentsResponse", "ListGuestsResponse", @@ -438,10 +424,11 @@ "TeamMembershipRole", "TestWebhookResponse", "Token", - "UnverifiedAuthenticator", "UpdateAccountParams", "UpdateAccountParamsExecutionRegion", "UpdateAccountResponse", + "UpdateAppEnvironmentParams", + "UpdateAppEnvironmentResponse", "UpdateAppParams", "UpdateAppResponse", "UpdateCatalogParams", @@ -453,8 +440,6 @@ "UpdateMyTeamInvitationResponse", "UpdateOrganizationParams", "UpdateOrganizationResponse", - "UpdatePasswordResetParams", - "UpdatePasswordResetResponse", "UpdatePlanParams", "UpdatePlanResponse", "UpdateScheduleParams", @@ -474,10 +459,9 @@ "UpdateWebhookParams", "UpdateWebhookResponse", "UsageLimit", + "UsageMetricTimeSeriesPoint", + "UsageMetricTimeSeriesPointName", "User", - "VerifiedAuthenticator", - "VerifyEmailParams", - "VerifyEmailResponse", "Webhook", "WebhookState", ) diff --git a/src/tower/tower_api_client/models/cancel_run_response.py b/src/tower/tower_api_client/models/cancel_run_response.py index a6a509e3..1d2a63a5 100644 --- a/src/tower/tower_api_client/models/cancel_run_response.py +++ b/src/tower/tower_api_client/models/cancel_run_response.py @@ -18,15 +18,19 @@ class CancelRunResponse: """ Attributes: + cancelled_child_runs (int): Number of descendant runs that were also cancelled as part of this cascade. run (Run): schema (str | Unset): A URL to the JSON Schema for this object. Example: https://api.tower.dev/v1/schemas/CancelRunResponse.json. """ + cancelled_child_runs: int run: Run schema: str | Unset = UNSET def to_dict(self) -> dict[str, Any]: + cancelled_child_runs = self.cancelled_child_runs + run = self.run.to_dict() schema = self.schema @@ -35,6 +39,7 @@ def to_dict(self) -> dict[str, Any]: field_dict.update( { + "cancelled_child_runs": cancelled_child_runs, "run": run, } ) @@ -48,11 +53,14 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: from ..models.run import Run d = dict(src_dict) + cancelled_child_runs = d.pop("cancelled_child_runs") + run = Run.from_dict(d.pop("run")) schema = d.pop("$schema", UNSET) cancel_run_response = cls( + cancelled_child_runs=cancelled_child_runs, run=run, schema=schema, ) diff --git a/src/tower/tower_api_client/models/create_authenticator_params.py b/src/tower/tower_api_client/models/create_authenticator_params.py deleted file mode 100644 index c425e583..00000000 --- a/src/tower/tower_api_client/models/create_authenticator_params.py +++ /dev/null @@ -1,62 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateAuthenticatorParams") - - -@_attrs_define -class CreateAuthenticatorParams: - """ - Attributes: - authenticator_url (str): The authenticator URL with an otpauth scheme that identifies this authenticator - verification_code (str): A code taken from the authenticator as verification that it's correctly configured. - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/CreateAuthenticatorParams.json. - """ - - authenticator_url: str - verification_code: str - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - authenticator_url = self.authenticator_url - - verification_code = self.verification_code - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "authenticator_url": authenticator_url, - "verification_code": verification_code, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - authenticator_url = d.pop("authenticator_url") - - verification_code = d.pop("verification_code") - - schema = d.pop("$schema", UNSET) - - create_authenticator_params = cls( - authenticator_url=authenticator_url, - verification_code=verification_code, - schema=schema, - ) - - return create_authenticator_params diff --git a/src/tower/tower_api_client/models/create_authenticator_response.py b/src/tower/tower_api_client/models/create_authenticator_response.py deleted file mode 100644 index f783573d..00000000 --- a/src/tower/tower_api_client/models/create_authenticator_response.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.verified_authenticator import VerifiedAuthenticator - - -T = TypeVar("T", bound="CreateAuthenticatorResponse") - - -@_attrs_define -class CreateAuthenticatorResponse: - """ - Attributes: - authenticator (VerifiedAuthenticator): - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/CreateAuthenticatorResponse.json. - """ - - authenticator: VerifiedAuthenticator - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - authenticator = self.authenticator.to_dict() - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "authenticator": authenticator, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.verified_authenticator import VerifiedAuthenticator - - d = dict(src_dict) - authenticator = VerifiedAuthenticator.from_dict(d.pop("authenticator")) - - schema = d.pop("$schema", UNSET) - - create_authenticator_response = cls( - authenticator=authenticator, - schema=schema, - ) - - return create_authenticator_response diff --git a/src/tower/tower_api_client/models/create_catalog_params_type.py b/src/tower/tower_api_client/models/create_catalog_params_type.py index 4c186f02..342cdc2a 100644 --- a/src/tower/tower_api_client/models/create_catalog_params_type.py +++ b/src/tower/tower_api_client/models/create_catalog_params_type.py @@ -5,6 +5,7 @@ class CreateCatalogParamsType(str, Enum): APACHE_POLARIS = "apache-polaris" CLOUDFLARE_R2_CATALOG = "cloudflare-r2-catalog" LAKEKEEPER = "lakekeeper" + S3_TABLES = "s3-tables" SNOWFLAKE_OPEN_CATALOG = "snowflake-open-catalog" TOWER_CATALOG = "tower-catalog" diff --git a/src/tower/tower_api_client/models/create_password_reset_params.py b/src/tower/tower_api_client/models/create_password_reset_params.py deleted file mode 100644 index 78c9bac3..00000000 --- a/src/tower/tower_api_client/models/create_password_reset_params.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreatePasswordResetParams") - - -@_attrs_define -class CreatePasswordResetParams: - """ - Attributes: - email (str): The email address to send the password reset email to - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/CreatePasswordResetParams.json. - """ - - email: str - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - email = self.email - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "email": email, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - email = d.pop("email") - - schema = d.pop("$schema", UNSET) - - create_password_reset_params = cls( - email=email, - schema=schema, - ) - - return create_password_reset_params diff --git a/src/tower/tower_api_client/models/create_password_reset_response.py b/src/tower/tower_api_client/models/create_password_reset_response.py deleted file mode 100644 index 07371f08..00000000 --- a/src/tower/tower_api_client/models/create_password_reset_response.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreatePasswordResetResponse") - - -@_attrs_define -class CreatePasswordResetResponse: - """ - Attributes: - ok (bool): A boolean indicating the request was successfully processed. - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/CreatePasswordResetResponse.json. - """ - - ok: bool - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - ok = self.ok - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "ok": ok, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - ok = d.pop("ok") - - schema = d.pop("$schema", UNSET) - - create_password_reset_response = cls( - ok=ok, - schema=schema, - ) - - return create_password_reset_response diff --git a/src/tower/tower_api_client/models/create_schedule_params.py b/src/tower/tower_api_client/models/create_schedule_params.py index f722db1d..79b0d774 100644 --- a/src/tower/tower_api_client/models/create_schedule_params.py +++ b/src/tower/tower_api_client/models/create_schedule_params.py @@ -26,8 +26,8 @@ class CreateScheduleParams: cron (str): The cron expression defining when the app should run schema (str | Unset): A URL to the JSON Schema for this object. Example: https://api.tower.dev/v1/schemas/CreateScheduleParams.json. - app_version (None | str | Unset): The specific app version to run (if omitted, will use the app's default - version) + app_version (None | str | Unset): This property is deprecated and ignored. Schedules inherit the version from + their environment. environment (str | Unset): The environment to run the app in Default: 'default'. name (None | str | Unset): The name for this schedule. Must be unique per environment. If not set, one will be generated for you. diff --git a/src/tower/tower_api_client/models/delete_authenticator_response.py b/src/tower/tower_api_client/models/delete_authenticator_response.py deleted file mode 100644 index e4076887..00000000 --- a/src/tower/tower_api_client/models/delete_authenticator_response.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.verified_authenticator import VerifiedAuthenticator - - -T = TypeVar("T", bound="DeleteAuthenticatorResponse") - - -@_attrs_define -class DeleteAuthenticatorResponse: - """ - Attributes: - authenticator (VerifiedAuthenticator): - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/DeleteAuthenticatorResponse.json. - """ - - authenticator: VerifiedAuthenticator - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - authenticator = self.authenticator.to_dict() - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "authenticator": authenticator, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.verified_authenticator import VerifiedAuthenticator - - d = dict(src_dict) - authenticator = VerifiedAuthenticator.from_dict(d.pop("authenticator")) - - schema = d.pop("$schema", UNSET) - - delete_authenticator_response = cls( - authenticator=authenticator, - schema=schema, - ) - - return delete_authenticator_response diff --git a/src/tower/tower_api_client/models/generate_authenticator_response.py b/src/tower/tower_api_client/models/generate_authenticator_response.py deleted file mode 100644 index 1a2a39f0..00000000 --- a/src/tower/tower_api_client/models/generate_authenticator_response.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.unverified_authenticator import UnverifiedAuthenticator - - -T = TypeVar("T", bound="GenerateAuthenticatorResponse") - - -@_attrs_define -class GenerateAuthenticatorResponse: - """ - Attributes: - authenticator (UnverifiedAuthenticator): - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/GenerateAuthenticatorResponse.json. - """ - - authenticator: UnverifiedAuthenticator - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - authenticator = self.authenticator.to_dict() - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "authenticator": authenticator, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.unverified_authenticator import UnverifiedAuthenticator - - d = dict(src_dict) - authenticator = UnverifiedAuthenticator.from_dict(d.pop("authenticator")) - - schema = d.pop("$schema", UNSET) - - generate_authenticator_response = cls( - authenticator=authenticator, - schema=schema, - ) - - return generate_authenticator_response diff --git a/src/tower/tower_api_client/models/generate_organization_usage_time_series_response.py b/src/tower/tower_api_client/models/generate_organization_usage_time_series_response.py new file mode 100644 index 00000000..eb71c6a8 --- /dev/null +++ b/src/tower/tower_api_client/models/generate_organization_usage_time_series_response.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.usage_metric_time_series_point import UsageMetricTimeSeriesPoint + + +T = TypeVar("T", bound="GenerateOrganizationUsageTimeSeriesResponse") + + +@_attrs_define +class GenerateOrganizationUsageTimeSeriesResponse: + """ + Attributes: + series (list[UsageMetricTimeSeriesPoint]): + schema (str | Unset): A URL to the JSON Schema for this object. Example: + https://api.tower.dev/v1/schemas/GenerateOrganizationUsageTimeSeriesResponse.json. + """ + + series: list[UsageMetricTimeSeriesPoint] + schema: str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + series = [] + for series_item_data in self.series: + series_item = series_item_data.to_dict() + series.append(series_item) + + schema = self.schema + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "series": series, + } + ) + if schema is not UNSET: + field_dict["$schema"] = schema + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.usage_metric_time_series_point import UsageMetricTimeSeriesPoint + + d = dict(src_dict) + series = [] + _series = d.pop("series") + for series_item_data in _series: + series_item = UsageMetricTimeSeriesPoint.from_dict(series_item_data) + + series.append(series_item) + + schema = d.pop("$schema", UNSET) + + generate_organization_usage_time_series_response = cls( + series=series, + schema=schema, + ) + + return generate_organization_usage_time_series_response diff --git a/src/tower/tower_api_client/models/generate_run_statistics_status_item.py b/src/tower/tower_api_client/models/generate_run_statistics_status_item.py index 84597b2a..3c11c0e1 100644 --- a/src/tower/tower_api_client/models/generate_run_statistics_status_item.py +++ b/src/tower/tower_api_client/models/generate_run_statistics_status_item.py @@ -9,6 +9,7 @@ class GenerateRunStatisticsStatusItem(str, Enum): PENDING = "pending" RETRYING = "retrying" RUNNING = "running" + STARTING = "starting" def __str__(self) -> str: return str(self.value) diff --git a/src/tower/tower_api_client/models/list_authenticators_response.py b/src/tower/tower_api_client/models/list_authenticators_response.py deleted file mode 100644 index ba5bcac4..00000000 --- a/src/tower/tower_api_client/models/list_authenticators_response.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.verified_authenticator import VerifiedAuthenticator - - -T = TypeVar("T", bound="ListAuthenticatorsResponse") - - -@_attrs_define -class ListAuthenticatorsResponse: - """ - Attributes: - authenticators (list[VerifiedAuthenticator]): - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/ListAuthenticatorsResponse.json. - """ - - authenticators: list[VerifiedAuthenticator] - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - authenticators = [] - for authenticators_item_data in self.authenticators: - authenticators_item = authenticators_item_data.to_dict() - authenticators.append(authenticators_item) - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "authenticators": authenticators, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.verified_authenticator import VerifiedAuthenticator - - d = dict(src_dict) - authenticators = [] - _authenticators = d.pop("authenticators") - for authenticators_item_data in _authenticators: - authenticators_item = VerifiedAuthenticator.from_dict( - authenticators_item_data - ) - - authenticators.append(authenticators_item) - - schema = d.pop("$schema", UNSET) - - list_authenticators_response = cls( - authenticators=authenticators, - schema=schema, - ) - - return list_authenticators_response diff --git a/src/tower/tower_api_client/models/list_runs_status_item.py b/src/tower/tower_api_client/models/list_runs_status_item.py index 46671e20..b05f9cca 100644 --- a/src/tower/tower_api_client/models/list_runs_status_item.py +++ b/src/tower/tower_api_client/models/list_runs_status_item.py @@ -9,6 +9,7 @@ class ListRunsStatusItem(str, Enum): PENDING = "pending" RETRYING = "retrying" RUNNING = "running" + STARTING = "starting" def __str__(self) -> str: return str(self.value) diff --git a/src/tower/tower_api_client/models/run.py b/src/tower/tower_api_client/models/run.py index 3eb0219b..748503d9 100644 --- a/src/tower/tower_api_client/models/run.py +++ b/src/tower/tower_api_client/models/run.py @@ -41,7 +41,8 @@ class Run: parameters (list[RunParameter]): Parameters used to invoke this run. run_id (str): scheduled_at (datetime.datetime): - started_at (datetime.datetime | None): + started_at (datetime.datetime | None): When the run started executing your code. + starting_at (datetime.datetime | None): When the runner environment started to get setup. status (RunStatus): status_group (RunStatusGroup): app_slug (str | Unset): This property is deprecated. Use app_name instead. @@ -68,6 +69,7 @@ class Run: run_id: str scheduled_at: datetime.datetime started_at: datetime.datetime | None + starting_at: datetime.datetime | None status: RunStatus status_group: RunStatusGroup app_slug: str | Unset = UNSET @@ -125,6 +127,12 @@ def to_dict(self) -> dict[str, Any]: else: started_at = self.started_at + starting_at: None | str + if isinstance(self.starting_at, datetime.datetime): + starting_at = self.starting_at.isoformat() + else: + starting_at = self.starting_at + status = self.status.value status_group = self.status_group.value @@ -170,6 +178,7 @@ def to_dict(self) -> dict[str, Any]: "run_id": run_id, "scheduled_at": scheduled_at, "started_at": started_at, + "starting_at": starting_at, "status": status, "status_group": status_group, } @@ -276,6 +285,21 @@ def _parse_started_at(data: object) -> datetime.datetime | None: started_at = _parse_started_at(d.pop("started_at")) + def _parse_starting_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + starting_at_type_0 = isoparse(data) + + return starting_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + starting_at = _parse_starting_at(d.pop("starting_at")) + status = RunStatus(d.pop("status")) status_group = RunStatusGroup(d.pop("status_group")) @@ -326,6 +350,7 @@ def _parse_subdomain(data: object) -> None | str | Unset: run_id=run_id, scheduled_at=scheduled_at, started_at=started_at, + starting_at=starting_at, status=status, status_group=status_group, app_slug=app_slug, diff --git a/src/tower/tower_api_client/models/run_attempt.py b/src/tower/tower_api_client/models/run_attempt.py index da912e6d..bcc3bff9 100644 --- a/src/tower/tower_api_client/models/run_attempt.py +++ b/src/tower/tower_api_client/models/run_attempt.py @@ -17,7 +17,8 @@ class RunAttempt: ended_at (datetime.datetime | None): When this attempt ended. exit_code (int | None): Exit code for this attempt. seq (int): 1-based attempt number. - started_at (datetime.datetime | None): When this attempt started. + started_at (datetime.datetime | None): When the run started executing your code. + starting_at (datetime.datetime | None): When the runner environment started to get setup. status (str): Terminal status of this attempt. """ @@ -25,6 +26,7 @@ class RunAttempt: exit_code: int | None seq: int started_at: datetime.datetime | None + starting_at: datetime.datetime | None status: str def to_dict(self) -> dict[str, Any]: @@ -45,6 +47,12 @@ def to_dict(self) -> dict[str, Any]: else: started_at = self.started_at + starting_at: None | str + if isinstance(self.starting_at, datetime.datetime): + starting_at = self.starting_at.isoformat() + else: + starting_at = self.starting_at + status = self.status field_dict: dict[str, Any] = {} @@ -55,6 +63,7 @@ def to_dict(self) -> dict[str, Any]: "exit_code": exit_code, "seq": seq, "started_at": started_at, + "starting_at": starting_at, "status": status, } ) @@ -104,6 +113,21 @@ def _parse_started_at(data: object) -> datetime.datetime | None: started_at = _parse_started_at(d.pop("started_at")) + def _parse_starting_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + starting_at_type_0 = isoparse(data) + + return starting_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + starting_at = _parse_starting_at(d.pop("starting_at")) + status = d.pop("status") run_attempt = cls( @@ -111,6 +135,7 @@ def _parse_started_at(data: object) -> datetime.datetime | None: exit_code=exit_code, seq=seq, started_at=started_at, + starting_at=starting_at, status=status, ) diff --git a/src/tower/tower_api_client/models/run_parameter.py b/src/tower/tower_api_client/models/run_parameter.py index f668ccc1..6d805c9b 100644 --- a/src/tower/tower_api_client/models/run_parameter.py +++ b/src/tower/tower_api_client/models/run_parameter.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, TypeVar +from typing import Any, TypeVar, cast from attrs import define as _attrs_define @@ -17,11 +17,14 @@ class RunParameter: name (str): value (str): hidden (bool | Unset): Whether this parameter is hidden/secret. Defaults to false. Default: False. + is_override (bool | None | Unset): Whether this parameter's value was supplied as an override at run/schedule + creation time (true) or comes from the app version's default (false). """ name: str value: str hidden: bool | Unset = False + is_override: bool | None | Unset = UNSET def to_dict(self) -> dict[str, Any]: name = self.name @@ -30,6 +33,12 @@ def to_dict(self) -> dict[str, Any]: hidden = self.hidden + is_override: bool | None | Unset + if isinstance(self.is_override, Unset): + is_override = UNSET + else: + is_override = self.is_override + field_dict: dict[str, Any] = {} field_dict.update( @@ -40,6 +49,8 @@ def to_dict(self) -> dict[str, Any]: ) if hidden is not UNSET: field_dict["hidden"] = hidden + if is_override is not UNSET: + field_dict["is_override"] = is_override return field_dict @@ -52,10 +63,20 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: hidden = d.pop("hidden", UNSET) + def _parse_is_override(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_override = _parse_is_override(d.pop("is_override", UNSET)) + run_parameter = cls( name=name, value=value, hidden=hidden, + is_override=is_override, ) return run_parameter diff --git a/src/tower/tower_api_client/models/run_results.py b/src/tower/tower_api_client/models/run_results.py index 37c69711..9cdc3f01 100644 --- a/src/tower/tower_api_client/models/run_results.py +++ b/src/tower/tower_api_client/models/run_results.py @@ -19,6 +19,7 @@ class RunResults: pending (int): retrying (int): running (int): + starting (int): """ cancelled: int @@ -28,6 +29,7 @@ class RunResults: pending: int retrying: int running: int + starting: int def to_dict(self) -> dict[str, Any]: cancelled = self.cancelled @@ -44,6 +46,8 @@ def to_dict(self) -> dict[str, Any]: running = self.running + starting = self.starting + field_dict: dict[str, Any] = {} field_dict.update( @@ -55,6 +59,7 @@ def to_dict(self) -> dict[str, Any]: "pending": pending, "retrying": retrying, "running": running, + "starting": starting, } ) @@ -77,6 +82,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: running = d.pop("running") + starting = d.pop("starting") + run_results = cls( cancelled=cancelled, crashed=crashed, @@ -85,6 +92,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: pending=pending, retrying=retrying, running=running, + starting=starting, ) return run_results diff --git a/src/tower/tower_api_client/models/run_status.py b/src/tower/tower_api_client/models/run_status.py index 1cad2eb3..99e6d8aa 100644 --- a/src/tower/tower_api_client/models/run_status.py +++ b/src/tower/tower_api_client/models/run_status.py @@ -10,6 +10,7 @@ class RunStatus(str, Enum): RETRYING = "retrying" RUNNING = "running" SCHEDULED = "scheduled" + STARTING = "starting" def __str__(self) -> str: return str(self.value) diff --git a/src/tower/tower_api_client/models/run_timeseries_point.py b/src/tower/tower_api_client/models/run_timeseries_point.py index de83c155..99b5bc63 100644 --- a/src/tower/tower_api_client/models/run_timeseries_point.py +++ b/src/tower/tower_api_client/models/run_timeseries_point.py @@ -23,6 +23,7 @@ class RunTimeseriesPoint: retrying (int): running (int): scheduled (int): + starting (int): """ cancelled: int @@ -34,6 +35,7 @@ class RunTimeseriesPoint: retrying: int running: int scheduled: int + starting: int def to_dict(self) -> dict[str, Any]: cancelled = self.cancelled @@ -54,6 +56,8 @@ def to_dict(self) -> dict[str, Any]: scheduled = self.scheduled + starting = self.starting + field_dict: dict[str, Any] = {} field_dict.update( @@ -67,6 +71,7 @@ def to_dict(self) -> dict[str, Any]: "retrying": retrying, "running": running, "scheduled": scheduled, + "starting": starting, } ) @@ -93,6 +98,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: scheduled = d.pop("scheduled") + starting = d.pop("starting") + run_timeseries_point = cls( cancelled=cancelled, crashed=crashed, @@ -103,6 +110,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: retrying=retrying, running=running, scheduled=scheduled, + starting=starting, ) return run_timeseries_point diff --git a/src/tower/tower_api_client/models/schedule.py b/src/tower/tower_api_client/models/schedule.py index 42f77665..d34ea239 100644 --- a/src/tower/tower_api_client/models/schedule.py +++ b/src/tower/tower_api_client/models/schedule.py @@ -35,7 +35,8 @@ class Schedule: timezone (str): The IANA timezone identifier that the cron expression is evaluated in (e.g., 'America/New_York', 'Europe/London'). Defaults to 'UTC'. updated_at (datetime.datetime): The timestamp when the schedule was last updated - app_version (str | Unset): The specific app version to run, or null for the default version + app_version (str | Unset): This property is deprecated. Schedules inherit the version from their environment. + This field returns the environment's current version. parameters (list[RunParameter] | Unset): The parameters to pass when running the app """ diff --git a/src/tower/tower_api_client/models/search_runs_status_item.py b/src/tower/tower_api_client/models/search_runs_status_item.py index afac0331..b1b65541 100644 --- a/src/tower/tower_api_client/models/search_runs_status_item.py +++ b/src/tower/tower_api_client/models/search_runs_status_item.py @@ -9,6 +9,7 @@ class SearchRunsStatusItem(str, Enum): PENDING = "pending" RETRYING = "retrying" RUNNING = "running" + STARTING = "starting" def __str__(self) -> str: return str(self.value) diff --git a/src/tower/tower_api_client/models/unverified_authenticator.py b/src/tower/tower_api_client/models/unverified_authenticator.py deleted file mode 100644 index 6fd77faa..00000000 --- a/src/tower/tower_api_client/models/unverified_authenticator.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define - -T = TypeVar("T", bound="UnverifiedAuthenticator") - - -@_attrs_define -class UnverifiedAuthenticator: - """ - Attributes: - issuer (str): The issuer of the unverified authenticator. - key (str): The key of the unverified authenticator. - label (str): The label that is used for this unverified authenticator. - url (str): The full URL of the authenticator. - """ - - issuer: str - key: str - label: str - url: str - - def to_dict(self) -> dict[str, Any]: - issuer = self.issuer - - key = self.key - - label = self.label - - url = self.url - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "issuer": issuer, - "key": key, - "label": label, - "url": url, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - issuer = d.pop("issuer") - - key = d.pop("key") - - label = d.pop("label") - - url = d.pop("url") - - unverified_authenticator = cls( - issuer=issuer, - key=key, - label=label, - url=url, - ) - - return unverified_authenticator diff --git a/src/tower/tower_api_client/models/update_password_reset_response.py b/src/tower/tower_api_client/models/update_app_environment_params.py similarity index 62% rename from src/tower/tower_api_client/models/update_password_reset_response.py rename to src/tower/tower_api_client/models/update_app_environment_params.py index 3e18fc74..14fc1f28 100644 --- a/src/tower/tower_api_client/models/update_password_reset_response.py +++ b/src/tower/tower_api_client/models/update_app_environment_params.py @@ -7,23 +7,23 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="UpdatePasswordResetResponse") +T = TypeVar("T", bound="UpdateAppEnvironmentParams") @_attrs_define -class UpdatePasswordResetResponse: +class UpdateAppEnvironmentParams: """ Attributes: - ok (bool): A boolean indicating the request was successfully processed. + version (str): The version to deploy to this environment, e.g. 'v1', 'v2'. schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/UpdatePasswordResetResponse.json. + https://api.tower.dev/v1/schemas/UpdateAppEnvironmentParams.json. """ - ok: bool + version: str schema: str | Unset = UNSET def to_dict(self) -> dict[str, Any]: - ok = self.ok + version = self.version schema = self.schema @@ -31,7 +31,7 @@ def to_dict(self) -> dict[str, Any]: field_dict.update( { - "ok": ok, + "version": version, } ) if schema is not UNSET: @@ -42,13 +42,13 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - ok = d.pop("ok") + version = d.pop("version") schema = d.pop("$schema", UNSET) - update_password_reset_response = cls( - ok=ok, + update_app_environment_params = cls( + version=version, schema=schema, ) - return update_password_reset_response + return update_app_environment_params diff --git a/src/tower/tower_api_client/models/delete_authenticator_params.py b/src/tower/tower_api_client/models/update_app_environment_response.py similarity index 55% rename from src/tower/tower_api_client/models/delete_authenticator_params.py rename to src/tower/tower_api_client/models/update_app_environment_response.py index 375f3c9b..a64310e4 100644 --- a/src/tower/tower_api_client/models/delete_authenticator_params.py +++ b/src/tower/tower_api_client/models/update_app_environment_response.py @@ -7,23 +7,27 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="DeleteAuthenticatorParams") +T = TypeVar("T", bound="UpdateAppEnvironmentResponse") @_attrs_define -class DeleteAuthenticatorParams: +class UpdateAppEnvironmentResponse: """ Attributes: - authenticator_id (str): The ID of the authenticator to delete + environment (str): + version (str): schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/DeleteAuthenticatorParams.json. + https://api.tower.dev/v1/schemas/UpdateAppEnvironmentResponse.json. """ - authenticator_id: str + environment: str + version: str schema: str | Unset = UNSET def to_dict(self) -> dict[str, Any]: - authenticator_id = self.authenticator_id + environment = self.environment + + version = self.version schema = self.schema @@ -31,7 +35,8 @@ def to_dict(self) -> dict[str, Any]: field_dict.update( { - "authenticator_id": authenticator_id, + "environment": environment, + "version": version, } ) if schema is not UNSET: @@ -42,13 +47,16 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - authenticator_id = d.pop("authenticator_id") + environment = d.pop("environment") + + version = d.pop("version") schema = d.pop("$schema", UNSET) - delete_authenticator_params = cls( - authenticator_id=authenticator_id, + update_app_environment_response = cls( + environment=environment, + version=version, schema=schema, ) - return delete_authenticator_params + return update_app_environment_response diff --git a/src/tower/tower_api_client/models/update_password_reset_params.py b/src/tower/tower_api_client/models/update_password_reset_params.py deleted file mode 100644 index a7dd2720..00000000 --- a/src/tower/tower_api_client/models/update_password_reset_params.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="UpdatePasswordResetParams") - - -@_attrs_define -class UpdatePasswordResetParams: - """ - Attributes: - password (str): The new password that you want to set for your account - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/UpdatePasswordResetParams.json. - """ - - password: str - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - password = self.password - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "password": password, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - password = d.pop("password") - - schema = d.pop("$schema", UNSET) - - update_password_reset_params = cls( - password=password, - schema=schema, - ) - - return update_password_reset_params diff --git a/src/tower/tower_api_client/models/update_schedule_params.py b/src/tower/tower_api_client/models/update_schedule_params.py index 23a80a7e..fdb50089 100644 --- a/src/tower/tower_api_client/models/update_schedule_params.py +++ b/src/tower/tower_api_client/models/update_schedule_params.py @@ -24,8 +24,8 @@ class UpdateScheduleParams: Attributes: schema (str | Unset): A URL to the JSON Schema for this object. Example: https://api.tower.dev/v1/schemas/UpdateScheduleParams.json. - app_version (None | str | Unset): The specific app version to run (if omitted, will use the app's default - version) + app_version (None | str | Unset): This property is deprecated and ignored. Schedules inherit the version from + their environment. cron (str | Unset): The cron expression defining when the app should run environment (str | Unset): The environment to run the app in Default: 'default'. name (None | str | Unset): The name for this schedule. Must be unique per team. diff --git a/src/tower/tower_api_client/models/usage_metric_time_series_point.py b/src/tower/tower_api_client/models/usage_metric_time_series_point.py new file mode 100644 index 00000000..862b7c15 --- /dev/null +++ b/src/tower/tower_api_client/models/usage_metric_time_series_point.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from dateutil.parser import isoparse + +from ..models.usage_metric_time_series_point_name import UsageMetricTimeSeriesPointName + +T = TypeVar("T", bound="UsageMetricTimeSeriesPoint") + + +@_attrs_define +class UsageMetricTimeSeriesPoint: + """ + Attributes: + date (datetime.datetime): + name (UsageMetricTimeSeriesPointName): + value (int): + """ + + date: datetime.datetime + name: UsageMetricTimeSeriesPointName + value: int + + def to_dict(self) -> dict[str, Any]: + date = self.date.isoformat() + + name = self.name.value + + value = self.value + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "date": date, + "name": name, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + date = isoparse(d.pop("date")) + + name = UsageMetricTimeSeriesPointName(d.pop("name")) + + value = d.pop("value") + + usage_metric_time_series_point = cls( + date=date, + name=name, + value=value, + ) + + return usage_metric_time_series_point diff --git a/src/tower/tower_api_client/models/usage_metric_time_series_point_name.py b/src/tower/tower_api_client/models/usage_metric_time_series_point_name.py new file mode 100644 index 00000000..4e55c479 --- /dev/null +++ b/src/tower/tower_api_client/models/usage_metric_time_series_point_name.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class UsageMetricTimeSeriesPointName(str, Enum): + RUN_SECONDS = "run_seconds" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/tower/tower_api_client/models/verified_authenticator.py b/src/tower/tower_api_client/models/verified_authenticator.py deleted file mode 100644 index d9ee4201..00000000 --- a/src/tower/tower_api_client/models/verified_authenticator.py +++ /dev/null @@ -1,68 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from dateutil.parser import isoparse - -T = TypeVar("T", bound="VerifiedAuthenticator") - - -@_attrs_define -class VerifiedAuthenticator: - """ - Attributes: - created_at (datetime.datetime): The ISO8601 timestamp indicating when this authenticator was created - id (str): The ID of this authenticator - issuer (str): The issuer of the unverified authenticator. - label (str): The label that is used for this unverified authenticator. - """ - - created_at: datetime.datetime - id: str - issuer: str - label: str - - def to_dict(self) -> dict[str, Any]: - created_at = self.created_at.isoformat() - - id = self.id - - issuer = self.issuer - - label = self.label - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "created_at": created_at, - "id": id, - "issuer": issuer, - "label": label, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - created_at = isoparse(d.pop("created_at")) - - id = d.pop("id") - - issuer = d.pop("issuer") - - label = d.pop("label") - - verified_authenticator = cls( - created_at=created_at, - id=id, - issuer=issuer, - label=label, - ) - - return verified_authenticator diff --git a/src/tower/tower_api_client/models/verify_email_params.py b/src/tower/tower_api_client/models/verify_email_params.py deleted file mode 100644 index 32e1b394..00000000 --- a/src/tower/tower_api_client/models/verify_email_params.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="VerifyEmailParams") - - -@_attrs_define -class VerifyEmailParams: - """ - Attributes: - code (str): - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/VerifyEmailParams.json. - """ - - code: str - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - code = self.code - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "code": code, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - code = d.pop("code") - - schema = d.pop("$schema", UNSET) - - verify_email_params = cls( - code=code, - schema=schema, - ) - - return verify_email_params diff --git a/src/tower/tower_api_client/models/verify_email_response.py b/src/tower/tower_api_client/models/verify_email_response.py deleted file mode 100644 index 40f4135d..00000000 --- a/src/tower/tower_api_client/models/verify_email_response.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.user import User - - -T = TypeVar("T", bound="VerifyEmailResponse") - - -@_attrs_define -class VerifyEmailResponse: - """ - Attributes: - user (User): - schema (str | Unset): A URL to the JSON Schema for this object. Example: - https://api.tower.dev/v1/schemas/VerifyEmailResponse.json. - """ - - user: User - schema: str | Unset = UNSET - - def to_dict(self) -> dict[str, Any]: - user = self.user.to_dict() - - schema = self.schema - - field_dict: dict[str, Any] = {} - - field_dict.update( - { - "user": user, - } - ) - if schema is not UNSET: - field_dict["$schema"] = schema - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.user import User - - d = dict(src_dict) - user = User.from_dict(d.pop("user")) - - schema = d.pop("$schema", UNSET) - - verify_email_response = cls( - user=user, - schema=schema, - ) - - return verify_email_response diff --git a/tests/integration/features/cli_pagination.feature b/tests/integration/features/cli_pagination.feature new file mode 100644 index 00000000..f71262e8 --- /dev/null +++ b/tests/integration/features/cli_pagination.feature @@ -0,0 +1,16 @@ +@serial @pagination +Feature: CLI Apps List Pagination + As a developer using Tower CLI + I want all of my apps to be returned from list commands + So that I don't miss apps due to pagination limits + + Scenario: CLI apps list returns every app across multiple pages + Given I have created 3 apps via CLI + When I run "tower --page 1 --page-size 2 apps list" via CLI + Then the output should contain all created app names + + Scenario: CLI apps list in JSON mode returns every app across multiple pages + Given I have created 3 apps via CLI + When I run "tower --page 1 --page-size 2 apps list --json" via CLI + Then the output should be valid JSON + And the JSON should contain all created app names diff --git a/tests/integration/features/environment.py b/tests/integration/features/environment.py index 62fbffbb..b6fb2d71 100644 --- a/tests/integration/features/environment.py +++ b/tests/integration/features/environment.py @@ -26,6 +26,24 @@ def before_scenario(context, scenario): def after_scenario(context, scenario): import shutil + # Delete any apps created by the scenario via "I have created N apps via CLI". + if getattr(context, "created_app_names", None): + env = os.environ.copy() + env["TOWER_URL"] = context.tower_url + test_home = Path(__file__).parent.parent / "test-home" + env["HOME"] = str(test_home.absolute()) + for name in context.created_app_names: + try: + subprocess.run( + [context.tower_binary, "apps", "delete", name], + env=env, + capture_output=True, + timeout=30, + ) + except subprocess.TimeoutExpired: + pass + context.created_app_names = [] + # Clean up any MCP servers started by this scenario for attr in ["http_mcp_process", "sse_mcp_process"]: if hasattr(context, attr): diff --git a/tests/integration/features/steps/cli_steps.py b/tests/integration/features/steps/cli_steps.py index b9a24d39..c4a38eb0 100644 --- a/tests/integration/features/steps/cli_steps.py +++ b/tests/integration/features/steps/cli_steps.py @@ -9,7 +9,8 @@ import re from datetime import datetime from pathlib import Path -from behave import given, when, then +import requests +from behave import given, when, then, step from dirty_equals import IsStr, IsPartialDict @@ -432,3 +433,67 @@ def step_app_description_should_be(context, expected_description): assert ( actual_description == expected_description ), f"Expected description '{expected_description}', got '{actual_description}'" + + +# Pagination test steps + + +def _pagination_env(context): + env = os.environ.copy() + env["TOWER_URL"] = context.tower_url + test_home = Path(__file__).parent.parent.parent / "test-home" + env["HOME"] = str(test_home.absolute()) + return env + + +@step("I have created {count:d} apps via CLI") +def step_create_apps_via_cli(context, count): + """Create a number of apps via the real CLI so the list command has something to return.""" + env = _pagination_env(context) + context.created_app_names = [] + for i in range(count): + name = f"pagination-test-app-{i:03d}" + # Best-effort delete in case a prior run left this name behind. + subprocess.run( + [context.tower_binary, "apps", "delete", name], + env=env, + capture_output=True, + ) + result = subprocess.run( + [context.tower_binary, "apps", "create", "--name", name], + env=env, + capture_output=True, + text=True, + timeout=60, + ) + assert ( + result.returncode == 0 + ), f"Failed to create {name}: {result.stdout}\n{result.stderr}" + context.created_app_names.append(name) + + +@step("the output should contain all created app names") +def step_output_should_contain_all_created_apps(context): + output = re.sub(r"\x1b\[[0-9;]*[A-Za-z]", "", context.cli_output) + missing = [name for name in context.created_app_names if name not in output] + assert not missing, ( + f"Missing {len(missing)} apps from output: {missing}\n" + f"Full output: {output[:2000]}" + ) + + +@step("the JSON should contain all created app names") +def step_json_should_contain_all_created_apps(context): + data = parse_cli_json(context) + assert isinstance(data, list), f"Expected JSON array, got: {type(data)}" + listed = set() + for entry in data: + if not isinstance(entry, dict): + continue + # apps list returns AppSummary objects shaped as {"app": {"name": ...}, "runs": [...]}. + if "app" in entry and isinstance(entry["app"], dict): + listed.add(entry["app"].get("name")) + else: + listed.add(entry.get("name")) + missing = [name for name in context.created_app_names if name not in listed] + assert not missing, f"Missing {len(missing)} apps from JSON: {missing}" diff --git a/tests/integration/run_tests.py b/tests/integration/run_tests.py index 9b1174d4..b41b2544 100755 --- a/tests/integration/run_tests.py +++ b/tests/integration/run_tests.py @@ -188,10 +188,34 @@ def main(): else: log("Running integration tests...") - result = subprocess.run( - ["behave", str(test_dir)] + args, cwd=Path(__file__).parent, env=env + # Run parallel tests first (exclude @serial tagged features) + parallel_result = subprocess.run( + ["behave", str(test_dir), "--tags=~@serial"] + args, + cwd=Path(__file__).parent, + env=env, + ) + + # Run @serial tagged features sequentially (no --jobs flag) + serial_args = [a for a in args if a not in ("--jobs", "-j") and not a.isdigit()] + # Remove --jobs N pair from args + serial_args = [] + skip_next = False + for a in args: + if skip_next: + skip_next = False + continue + if a in ("--jobs", "-j"): + skip_next = True + continue + serial_args.append(a) + + serial_result = subprocess.run( + ["behave", str(test_dir), "--tags=@serial"] + serial_args, + cwd=Path(__file__).parent, + env=env, ) - return result.returncode + + return parallel_result.returncode or serial_result.returncode except KeyboardInterrupt: log("Tests interrupted by user") diff --git a/tests/mock-api-server/main.py b/tests/mock-api-server/main.py index 7faff7d0..ba386f7a 100644 --- a/tests/mock-api-server/main.py +++ b/tests/mock-api-server/main.py @@ -69,6 +69,7 @@ async def log_requests(request: Request, call_next): "pending": 0, "retrying": 0, "running": 0, + "starting": 0, }, "subdomain": None, "is_externally_accessible": False, @@ -111,20 +112,22 @@ async def read_root(): # Placeholder for /v1/apps endpoints @app.get("/v1/apps") -async def list_apps(): - # Format apps as AppSummary objects +async def list_apps(page: Optional[int] = None, page_size: Optional[int] = None): + # Format apps as AppSummary objects (matching real API list format) app_summaries = [] + # Fields to exclude from list view (real API doesn't return these in list) + list_excluded_fields = {"run_results"} for app_data in mock_apps_db.values(): - app_summaries.append({"app": app_data, "runs": []}) # Empty runs for list view + app_for_list = { + k: v for k, v in app_data.items() if k not in list_excluded_fields + } + app_summaries.append({"app": app_for_list, "runs": []}) + + page_items, pages = paginate(app_summaries, page, page_size) return { - "apps": app_summaries, - "pages": { - "page": 1, - "total": len(mock_apps_db), - "num_pages": 1, - "page_size": 20, - }, + "apps": page_items, + "pages": pages, } @@ -160,6 +163,7 @@ async def create_app(app_data: Dict[str, Any]): "pending": 0, "retrying": 0, "running": 0, + "starting": 0, }, "schedule": None, "short_description": description or "", @@ -283,6 +287,7 @@ async def run_app(name: str, run_params: Dict[str, Any]): "created_at": datetime.datetime.now().isoformat(), "scheduled_at": datetime.datetime.now().isoformat(), "cancelled_at": None, + "starting_at": datetime.datetime.now().isoformat(), "started_at": datetime.datetime.now().isoformat(), "ended_at": None, "app_version": mock_apps_db[name].get("version", "1.0.0"), @@ -355,7 +360,7 @@ async def cancel_run(name: str, seq: int): run_data["status"] = "cancelled" run_data["status_group"] = "successful" run_data["cancelled_at"] = now_iso() - return {"run": run_data} + return {"run": run_data, "cancelled_child_runs": 0} raise HTTPException( status_code=404, detail=f"Run sequence {seq} not found for app '{name}'" @@ -364,15 +369,11 @@ async def cancel_run(name: str, seq: int): # Placeholder for /secrets endpoints @app.get("/v1/secrets") -async def list_secrets(): +async def list_secrets(page: Optional[int] = None, page_size: Optional[int] = None): + items, pages = paginate(list(mock_secrets_db.values()), page, page_size) return { - "secrets": list(mock_secrets_db.values()), - "pages": { - "page": 1, - "total": len(mock_secrets_db), - "num_pages": 1, - "page_size": 20, - }, + "secrets": items, + "pages": pages, } @@ -413,8 +414,9 @@ async def delete_secret(name: str, environment: str = "default"): # Placeholder for /teams endpoints @app.get("/v1/teams") -async def list_teams(): - return {"teams": list(mock_teams_db.values())} +async def list_teams(page: Optional[int] = None, page_size: Optional[int] = None): + items, pages = paginate(list(mock_teams_db.values()), page, page_size) + return {"teams": items, "pages": pages} @app.post("/v1/teams") @@ -458,6 +460,38 @@ async def describe_secrets_key(): return {"public_key": mock_public_key} +def paginate(items: list, page: Optional[int], page_size: Optional[int]) -> tuple: + """Apply pagination to a list of items. Returns (page_items, pages_metadata). + + Matches the real API: page is 1-indexed; page=0 or page=None means + "no pagination, return everything". + """ + if page_size is None or page_size <= 0: + page_size = 20 + + total = len(items) + + if page is None or page == 0: + return items, { + "page": 0, + "total": total, + "num_pages": 1, + "page_size": page_size, + } + + num_pages = max(1, (total + page_size - 1) // page_size) + start = (page - 1) * page_size + end = start + page_size + page_items = items[start:end] + + return page_items, { + "page": page, + "total": total, + "num_pages": num_pages, + "page_size": page_size, + } + + def empty_paginated_response(key: str): """Create empty paginated response for any resource type.""" return {key: [], "pages": {"page": 1, "total": 0, "num_pages": 1, "page_size": 20}} @@ -638,16 +672,12 @@ async def stream_run_logs(name: str, seq: int): # Schedule endpoints @app.get("/v1/schedules") -async def list_schedules(): +async def list_schedules(page: Optional[int] = None, page_size: Optional[int] = None): """Mock endpoint for listing schedules.""" + items, pages = paginate(list(mock_schedules_db.values()), page, page_size) return { - "schedules": list(mock_schedules_db.values()), - "pages": { - "page": 1, - "total": len(mock_schedules_db), - "num_pages": 1, - "page_size": 20, - }, + "schedules": items, + "pages": pages, } diff --git a/tests/mock-api-server/pyproject.toml b/tests/mock-api-server/pyproject.toml index fc24c4b0..011d6f85 100644 --- a/tests/mock-api-server/pyproject.toml +++ b/tests/mock-api-server/pyproject.toml @@ -6,7 +6,7 @@ dependencies = [ "fastapi==0.111.0", "uvicorn==0.30.1", ] -requires-python = ">=3.9" +requires-python = ">=3.9,<3.14" [build-system] requires = ["setuptools>=61.0"] diff --git a/tests/mock-api-server/tower_mock_api.egg-info/PKG-INFO b/tests/mock-api-server/tower_mock_api.egg-info/PKG-INFO index 7d46deca..ebcad901 100644 --- a/tests/mock-api-server/tower_mock_api.egg-info/PKG-INFO +++ b/tests/mock-api-server/tower_mock_api.egg-info/PKG-INFO @@ -2,6 +2,6 @@ Metadata-Version: 2.4 Name: tower-mock-api Version: 0.1.0 Summary: A mock API server for Tower CLI testing. -Requires-Python: >=3.9 +Requires-Python: <3.14,>=3.9 Requires-Dist: fastapi==0.111.0 Requires-Dist: uvicorn==0.30.1 diff --git a/tests/mock-api-server/uv.lock b/tests/mock-api-server/uv.lock index 3c3a88c4..0f582d76 100644 --- a/tests/mock-api-server/uv.lock +++ b/tests/mock-api-server/uv.lock @@ -1,6 +1,6 @@ version = 1 -revision = 2 -requires-python = ">=3.9" +revision = 3 +requires-python = ">=3.9, <3.14" resolution-markers = [ "python_full_version >= '3.10'", "python_full_version < '3.10'", @@ -420,17 +420,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9c/5b/e398449080ce6b4c8fcadad57e51fa16f65768e1b142ba90b23ac5d10801/orjson-3.11.2-cp313-cp313-win32.whl", hash = "sha256:51dc033df2e4a4c91c0ba4f43247de99b3cbf42ee7a42ee2b2b2f76c8b2f2cb5", size = 124402, upload-time = "2025-08-12T15:11:44.036Z" }, { url = "https://files.pythonhosted.org/packages/b3/66/429e4608e124debfc4790bfc37131f6958e59510ba3b542d5fc163be8e5f/orjson-3.11.2-cp313-cp313-win_amd64.whl", hash = "sha256:29d91d74942b7436f29b5d1ed9bcfc3f6ef2d4f7c4997616509004679936650d", size = 119498, upload-time = "2025-08-12T15:11:45.864Z" }, { url = "https://files.pythonhosted.org/packages/7b/04/f8b5f317cce7ad3580a9ad12d7e2df0714dfa8a83328ecddd367af802f5b/orjson-3.11.2-cp313-cp313-win_arm64.whl", hash = "sha256:4ca4fb5ac21cd1e48028d4f708b1bb13e39c42d45614befd2ead004a8bba8535", size = 114051, upload-time = "2025-08-12T15:11:47.555Z" }, - { url = "https://files.pythonhosted.org/packages/74/83/2c363022b26c3c25b3708051a19d12f3374739bb81323f05b284392080c0/orjson-3.11.2-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3dcba7101ea6a8d4ef060746c0f2e7aa8e2453a1012083e1ecce9726d7554cb7", size = 226406, upload-time = "2025-08-12T15:11:49.445Z" }, - { url = "https://files.pythonhosted.org/packages/b0/a7/aa3c973de0b33fc93b4bd71691665ffdfeae589ea9d0625584ab10a7d0f5/orjson-3.11.2-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:15d17bdb76a142e1f55d91913e012e6e6769659daa6bfef3ef93f11083137e81", size = 115788, upload-time = "2025-08-12T15:11:50.992Z" }, - { url = "https://files.pythonhosted.org/packages/ef/f2/e45f233dfd09fdbb052ec46352363dca3906618e1a2b264959c18f809d0b/orjson-3.11.2-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:53c9e81768c69d4b66b8876ec3c8e431c6e13477186d0db1089d82622bccd19f", size = 111318, upload-time = "2025-08-12T15:11:52.495Z" }, - { url = "https://files.pythonhosted.org/packages/3e/23/cf5a73c4da6987204cbbf93167f353ff0c5013f7c5e5ef845d4663a366da/orjson-3.11.2-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d4f13af59a7b84c1ca6b8a7ab70d608f61f7c44f9740cd42409e6ae7b6c8d8b7", size = 121231, upload-time = "2025-08-12T15:11:53.941Z" }, - { url = "https://files.pythonhosted.org/packages/40/1d/47468a398ae68a60cc21e599144e786e035bb12829cb587299ecebc088f1/orjson-3.11.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bde64aa469b5ee46cc960ed241fae3721d6a8801dacb2ca3466547a2535951e4", size = 119204, upload-time = "2025-08-12T15:11:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/4d/d9/f99433d89b288b5bc8836bffb32a643f805e673cf840ef8bab6e73ced0d1/orjson-3.11.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b5ca86300aeb383c8fa759566aca065878d3d98c3389d769b43f0a2e84d52c5f", size = 392237, upload-time = "2025-08-12T15:11:57.18Z" }, - { url = "https://files.pythonhosted.org/packages/d4/dc/1b9d80d40cebef603325623405136a29fb7d08c877a728c0943dd066c29a/orjson-3.11.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:24e32a558ebed73a6a71c8f1cbc163a7dd5132da5270ff3d8eeb727f4b6d1bc7", size = 134578, upload-time = "2025-08-12T15:11:58.844Z" }, - { url = "https://files.pythonhosted.org/packages/45/b3/72e7a4c5b6485ef4e83ef6aba7f1dd041002bad3eb5d1d106ca5b0fc02c6/orjson-3.11.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e36319a5d15b97e4344110517450396845cc6789aed712b1fbf83c1bd95792f6", size = 123799, upload-time = "2025-08-12T15:12:00.352Z" }, - { url = "https://files.pythonhosted.org/packages/c8/3e/a3d76b392e7acf9b34dc277171aad85efd6accc75089bb35b4c614990ea9/orjson-3.11.2-cp314-cp314-win32.whl", hash = "sha256:40193ada63fab25e35703454d65b6afc71dbc65f20041cb46c6d91709141ef7f", size = 124461, upload-time = "2025-08-12T15:12:01.854Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e3/75c6a596ff8df9e4a5894813ff56695f0a218e6ea99420b4a645c4f7795d/orjson-3.11.2-cp314-cp314-win_amd64.whl", hash = "sha256:7c8ac5f6b682d3494217085cf04dadae66efee45349ad4ee2a1da3c97e2305a8", size = 119494, upload-time = "2025-08-12T15:12:03.337Z" }, - { url = "https://files.pythonhosted.org/packages/5b/3d/9e74742fc261c5ca473c96bb3344d03995869e1dc6402772c60afb97736a/orjson-3.11.2-cp314-cp314-win_arm64.whl", hash = "sha256:21cf261e8e79284242e4cb1e5924df16ae28255184aafeff19be1405f6d33f67", size = 114046, upload-time = "2025-08-12T15:12:04.87Z" }, { url = "https://files.pythonhosted.org/packages/4f/08/8ebc6dcac0938376b7e61dff432c33958505ae4c185dda3fa1e6f46ac40b/orjson-3.11.2-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:957f10c7b5bce3d3f2ad577f3b307c784f5dabafcce3b836229c269c11841c86", size = 226498, upload-time = "2025-08-12T15:12:06.51Z" }, { url = "https://files.pythonhosted.org/packages/ff/74/a97c8e2bc75a27dfeeb1b289645053f1889125447f3b7484a2e34ac55d2a/orjson-3.11.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a669e31ab8eb466c9142ac7a4be2bb2758ad236a31ef40dcd4cf8774ab40f33", size = 111529, upload-time = "2025-08-12T15:12:08.21Z" }, { url = "https://files.pythonhosted.org/packages/78/c3/55121b5722a1a4e4610a411866cfeada5314dc498cd42435b590353009d2/orjson-3.11.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:adedf7d887416c51ad49de3c53b111887e0b63db36c6eb9f846a8430952303d8", size = 116213, upload-time = "2025-08-12T15:12:09.776Z" }, @@ -812,28 +801,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d8/50/8856e24bec5e2fc7f775d867aeb7a3f137359356200ac44658f1f2c834b2/ujson-5.11.0-cp313-cp313-win32.whl", hash = "sha256:8fa2af7c1459204b7a42e98263b069bd535ea0cd978b4d6982f35af5a04a4241", size = 39753, upload-time = "2025-08-20T11:56:01.345Z" }, { url = "https://files.pythonhosted.org/packages/5b/d8/1baee0f4179a4d0f5ce086832147b6cc9b7731c24ca08e14a3fdb8d39c32/ujson-5.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:34032aeca4510a7c7102bd5933f59a37f63891f30a0706fb46487ab6f0edf8f0", size = 43866, upload-time = "2025-08-20T11:56:02.552Z" }, { url = "https://files.pythonhosted.org/packages/a9/8c/6d85ef5be82c6d66adced3ec5ef23353ed710a11f70b0b6a836878396334/ujson-5.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:ce076f2df2e1aa62b685086fbad67f2b1d3048369664b4cdccc50707325401f9", size = 38363, upload-time = "2025-08-20T11:56:03.688Z" }, - { url = "https://files.pythonhosted.org/packages/28/08/4518146f4984d112764b1dfa6fb7bad691c44a401adadaa5e23ccd930053/ujson-5.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:65724738c73645db88f70ba1f2e6fb678f913281804d5da2fd02c8c5839af302", size = 55462, upload-time = "2025-08-20T11:56:04.873Z" }, - { url = "https://files.pythonhosted.org/packages/29/37/2107b9a62168867a692654d8766b81bd2fd1e1ba13e2ec90555861e02b0c/ujson-5.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29113c003ca33ab71b1b480bde952fbab2a0b6b03a4ee4c3d71687cdcbd1a29d", size = 53246, upload-time = "2025-08-20T11:56:06.054Z" }, - { url = "https://files.pythonhosted.org/packages/9b/f8/25583c70f83788edbe3ca62ce6c1b79eff465d78dec5eb2b2b56b3e98b33/ujson-5.11.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c44c703842024d796b4c78542a6fcd5c3cb948b9fc2a73ee65b9c86a22ee3638", size = 57631, upload-time = "2025-08-20T11:56:07.374Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ca/19b3a632933a09d696f10dc1b0dfa1d692e65ad507d12340116ce4f67967/ujson-5.11.0-cp314-cp314-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:e750c436fb90edf85585f5c62a35b35082502383840962c6983403d1bd96a02c", size = 59877, upload-time = "2025-08-20T11:56:08.534Z" }, - { url = "https://files.pythonhosted.org/packages/55/7a/4572af5324ad4b2bfdd2321e898a527050290147b4ea337a79a0e4e87ec7/ujson-5.11.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f278b31a7c52eb0947b2db55a5133fbc46b6f0ef49972cd1a80843b72e135aba", size = 57363, upload-time = "2025-08-20T11:56:09.758Z" }, - { url = "https://files.pythonhosted.org/packages/7b/71/a2b8c19cf4e1efe53cf439cdf7198ac60ae15471d2f1040b490c1f0f831f/ujson-5.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ab2cb8351d976e788669c8281465d44d4e94413718af497b4e7342d7b2f78018", size = 1036394, upload-time = "2025-08-20T11:56:11.168Z" }, - { url = "https://files.pythonhosted.org/packages/7a/3e/7b98668cba3bb3735929c31b999b374ebc02c19dfa98dfebaeeb5c8597ca/ujson-5.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:090b4d11b380ae25453100b722d0609d5051ffe98f80ec52853ccf8249dfd840", size = 1195837, upload-time = "2025-08-20T11:56:12.6Z" }, - { url = "https://files.pythonhosted.org/packages/a1/ea/8870f208c20b43571a5c409ebb2fe9b9dba5f494e9e60f9314ac01ea8f78/ujson-5.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:80017e870d882d5517d28995b62e4e518a894f932f1e242cbc802a2fd64d365c", size = 1088837, upload-time = "2025-08-20T11:56:14.15Z" }, - { url = "https://files.pythonhosted.org/packages/63/b6/c0e6607e37fa47929920a685a968c6b990a802dec65e9c5181e97845985d/ujson-5.11.0-cp314-cp314-win32.whl", hash = "sha256:1d663b96eb34c93392e9caae19c099ec4133ba21654b081956613327f0e973ac", size = 41022, upload-time = "2025-08-20T11:56:15.509Z" }, - { url = "https://files.pythonhosted.org/packages/4e/56/f4fe86b4c9000affd63e9219e59b222dc48b01c534533093e798bf617a7e/ujson-5.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:849e65b696f0d242833f1df4182096cedc50d414215d1371fca85c541fbff629", size = 45111, upload-time = "2025-08-20T11:56:16.597Z" }, - { url = "https://files.pythonhosted.org/packages/0a/f3/669437f0280308db4783b12a6d88c00730b394327d8334cc7a32ef218e64/ujson-5.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:e73df8648c9470af2b6a6bf5250d4744ad2cf3d774dcf8c6e31f018bdd04d764", size = 39682, upload-time = "2025-08-20T11:56:17.763Z" }, - { url = "https://files.pythonhosted.org/packages/6e/cd/e9809b064a89fe5c4184649adeb13c1b98652db3f8518980b04227358574/ujson-5.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:de6e88f62796372fba1de973c11138f197d3e0e1d80bcb2b8aae1e826096d433", size = 55759, upload-time = "2025-08-20T11:56:18.882Z" }, - { url = "https://files.pythonhosted.org/packages/1b/be/ae26a6321179ebbb3a2e2685b9007c71bcda41ad7a77bbbe164005e956fc/ujson-5.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:49e56ef8066f11b80d620985ae36869a3ff7e4b74c3b6129182ec5d1df0255f3", size = 53634, upload-time = "2025-08-20T11:56:20.012Z" }, - { url = "https://files.pythonhosted.org/packages/ae/e9/fb4a220ee6939db099f4cfeeae796ecb91e7584ad4d445d4ca7f994a9135/ujson-5.11.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1a325fd2c3a056cf6c8e023f74a0c478dd282a93141356ae7f16d5309f5ff823", size = 58547, upload-time = "2025-08-20T11:56:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/bd/f8/fc4b952b8f5fea09ea3397a0bd0ad019e474b204cabcb947cead5d4d1ffc/ujson-5.11.0-cp314-cp314t-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:a0af6574fc1d9d53f4ff371f58c96673e6d988ed2b5bf666a6143c782fa007e9", size = 60489, upload-time = "2025-08-20T11:56:22.342Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e5/af5491dfda4f8b77e24cf3da68ee0d1552f99a13e5c622f4cef1380925c3/ujson-5.11.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10f29e71ecf4ecd93a6610bd8efa8e7b6467454a363c3d6416db65de883eb076", size = 58035, upload-time = "2025-08-20T11:56:23.92Z" }, - { url = "https://files.pythonhosted.org/packages/c4/09/0945349dd41f25cc8c38d78ace49f14c5052c5bbb7257d2f466fa7bdb533/ujson-5.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1a0a9b76a89827a592656fe12e000cf4f12da9692f51a841a4a07aa4c7ecc41c", size = 1037212, upload-time = "2025-08-20T11:56:25.274Z" }, - { url = "https://files.pythonhosted.org/packages/49/44/8e04496acb3d5a1cbee3a54828d9652f67a37523efa3d3b18a347339680a/ujson-5.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b16930f6a0753cdc7d637b33b4e8f10d5e351e1fb83872ba6375f1e87be39746", size = 1196500, upload-time = "2025-08-20T11:56:27.517Z" }, - { url = "https://files.pythonhosted.org/packages/64/ae/4bc825860d679a0f208a19af2f39206dfd804ace2403330fdc3170334a2f/ujson-5.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:04c41afc195fd477a59db3a84d5b83a871bd648ef371cf8c6f43072d89144eef", size = 1089487, upload-time = "2025-08-20T11:56:29.07Z" }, - { url = "https://files.pythonhosted.org/packages/30/ed/5a057199fb0a5deabe0957073a1c1c1c02a3e99476cd03daee98ea21fa57/ujson-5.11.0-cp314-cp314t-win32.whl", hash = "sha256:aa6d7a5e09217ff93234e050e3e380da62b084e26b9f2e277d2606406a2fc2e5", size = 41859, upload-time = "2025-08-20T11:56:30.495Z" }, - { url = "https://files.pythonhosted.org/packages/aa/03/b19c6176bdf1dc13ed84b886e99677a52764861b6cc023d5e7b6ebda249d/ujson-5.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:48055e1061c1bb1f79e75b4ac39e821f3f35a9b82de17fce92c3140149009bec", size = 46183, upload-time = "2025-08-20T11:56:31.574Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ca/a0413a3874b2dc1708b8796ca895bf363292f9c70b2e8ca482b7dbc0259d/ujson-5.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1194b943e951092db611011cb8dbdb6cf94a3b816ed07906e14d3bc6ce0e90ab", size = 40264, upload-time = "2025-08-20T11:56:32.773Z" }, { url = "https://files.pythonhosted.org/packages/39/bf/c6f59cdf74ce70bd937b97c31c42fd04a5ed1a9222d0197e77e4bd899841/ujson-5.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65f3c279f4ed4bf9131b11972040200c66ae040368abdbb21596bf1564899694", size = 55283, upload-time = "2025-08-20T11:56:33.947Z" }, { url = "https://files.pythonhosted.org/packages/8d/c1/a52d55638c0c644b8a63059f95ad5ffcb4ad8f60d8bc3e8680f78e77cc75/ujson-5.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99c49400572cd77050894e16864a335225191fd72a818ea6423ae1a06467beac", size = 53168, upload-time = "2025-08-20T11:56:35.141Z" }, { url = "https://files.pythonhosted.org/packages/75/6c/e64e19a01d59c8187d01ffc752ee3792a09f5edaaac2a0402de004459dd7/ujson-5.11.0-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0654a2691fc252c3c525e3d034bb27b8a7546c9d3eb33cd29ce6c9feda361a6a", size = 57809, upload-time = "2025-08-20T11:56:36.293Z" }, @@ -987,26 +954,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/65/95/fe479b2664f19be4cf5ceeb21be05afd491d95f142e72d26a42f41b7c4f8/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20", size = 451864, upload-time = "2025-06-15T19:06:02.144Z" }, { url = "https://files.pythonhosted.org/packages/d3/8a/3c4af14b93a15ce55901cd7a92e1a4701910f1768c78fb30f61d2b79785b/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef", size = 625626, upload-time = "2025-06-15T19:06:03.578Z" }, { url = "https://files.pythonhosted.org/packages/da/f5/cf6aa047d4d9e128f4b7cde615236a915673775ef171ff85971d698f3c2c/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb", size = 622744, upload-time = "2025-06-15T19:06:05.066Z" }, - { url = "https://files.pythonhosted.org/packages/2c/00/70f75c47f05dea6fd30df90f047765f6fc2d6eb8b5a3921379b0b04defa2/watchfiles-1.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297", size = 402114, upload-time = "2025-06-15T19:06:06.186Z" }, - { url = "https://files.pythonhosted.org/packages/53/03/acd69c48db4a1ed1de26b349d94077cca2238ff98fd64393f3e97484cae6/watchfiles-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018", size = 393879, upload-time = "2025-06-15T19:06:07.369Z" }, - { url = "https://files.pythonhosted.org/packages/2f/c8/a9a2a6f9c8baa4eceae5887fecd421e1b7ce86802bcfc8b6a942e2add834/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0", size = 450026, upload-time = "2025-06-15T19:06:08.476Z" }, - { url = "https://files.pythonhosted.org/packages/fe/51/d572260d98388e6e2b967425c985e07d47ee6f62e6455cefb46a6e06eda5/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12", size = 457917, upload-time = "2025-06-15T19:06:09.988Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2d/4258e52917bf9f12909b6ec314ff9636276f3542f9d3807d143f27309104/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb", size = 483602, upload-time = "2025-06-15T19:06:11.088Z" }, - { url = "https://files.pythonhosted.org/packages/84/99/bee17a5f341a4345fe7b7972a475809af9e528deba056f8963d61ea49f75/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77", size = 596758, upload-time = "2025-06-15T19:06:12.197Z" }, - { url = "https://files.pythonhosted.org/packages/40/76/e4bec1d59b25b89d2b0716b41b461ed655a9a53c60dc78ad5771fda5b3e6/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92", size = 477601, upload-time = "2025-06-15T19:06:13.391Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fa/a514292956f4a9ce3c567ec0c13cce427c158e9f272062685a8a727d08fc/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e", size = 451936, upload-time = "2025-06-15T19:06:14.656Z" }, - { url = "https://files.pythonhosted.org/packages/32/5d/c3bf927ec3bbeb4566984eba8dd7a8eb69569400f5509904545576741f88/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b", size = 626243, upload-time = "2025-06-15T19:06:16.232Z" }, - { url = "https://files.pythonhosted.org/packages/e6/65/6e12c042f1a68c556802a84d54bb06d35577c81e29fba14019562479159c/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259", size = 623073, upload-time = "2025-06-15T19:06:17.457Z" }, - { url = "https://files.pythonhosted.org/packages/89/ab/7f79d9bf57329e7cbb0a6fd4c7bd7d0cee1e4a8ef0041459f5409da3506c/watchfiles-1.1.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f", size = 400872, upload-time = "2025-06-15T19:06:18.57Z" }, - { url = "https://files.pythonhosted.org/packages/df/d5/3f7bf9912798e9e6c516094db6b8932df53b223660c781ee37607030b6d3/watchfiles-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e", size = 392877, upload-time = "2025-06-15T19:06:19.55Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c5/54ec7601a2798604e01c75294770dbee8150e81c6e471445d7601610b495/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa", size = 449645, upload-time = "2025-06-15T19:06:20.66Z" }, - { url = "https://files.pythonhosted.org/packages/0a/04/c2f44afc3b2fce21ca0b7802cbd37ed90a29874f96069ed30a36dfe57c2b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8", size = 457424, upload-time = "2025-06-15T19:06:21.712Z" }, - { url = "https://files.pythonhosted.org/packages/9f/b0/eec32cb6c14d248095261a04f290636da3df3119d4040ef91a4a50b29fa5/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f", size = 481584, upload-time = "2025-06-15T19:06:22.777Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e2/ca4bb71c68a937d7145aa25709e4f5d68eb7698a25ce266e84b55d591bbd/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e", size = 596675, upload-time = "2025-06-15T19:06:24.226Z" }, - { url = "https://files.pythonhosted.org/packages/a1/dd/b0e4b7fb5acf783816bc950180a6cd7c6c1d2cf7e9372c0ea634e722712b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb", size = 477363, upload-time = "2025-06-15T19:06:25.42Z" }, - { url = "https://files.pythonhosted.org/packages/69/c4/088825b75489cb5b6a761a4542645718893d395d8c530b38734f19da44d2/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147", size = 452240, upload-time = "2025-06-15T19:06:26.552Z" }, - { url = "https://files.pythonhosted.org/packages/10/8c/22b074814970eeef43b7c44df98c3e9667c1f7bf5b83e0ff0201b0bd43f9/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8", size = 625607, upload-time = "2025-06-15T19:06:27.606Z" }, - { url = "https://files.pythonhosted.org/packages/32/fa/a4f5c2046385492b2273213ef815bf71a0d4c1943b784fb904e184e30201/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db", size = 623315, upload-time = "2025-06-15T19:06:29.076Z" }, { url = "https://files.pythonhosted.org/packages/47/8a/a45db804b9f0740f8408626ab2bca89c3136432e57c4673b50180bf85dd9/watchfiles-1.1.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:865c8e95713744cf5ae261f3067861e9da5f1370ba91fc536431e29b418676fa", size = 406400, upload-time = "2025-06-15T19:06:30.233Z" }, { url = "https://files.pythonhosted.org/packages/64/06/a08684f628fb41addd451845aceedc2407dc3d843b4b060a7c4350ddee0c/watchfiles-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42f92befc848bb7a19658f21f3e7bae80d7d005d13891c62c2cd4d4d0abb3433", size = 397920, upload-time = "2025-06-15T19:06:31.315Z" }, { url = "https://files.pythonhosted.org/packages/79/e6/e10d5675af653b1b07d4156906858041149ca222edaf8995877f2605ba9e/watchfiles-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa0cc8365ab29487eb4f9979fd41b22549853389e22d5de3f134a6796e1b05a4", size = 451196, upload-time = "2025-06-15T19:06:32.435Z" }, diff --git a/tests/tower/test_client.py b/tests/tower/test_client.py index beb48cc7..04e44e0d 100644 --- a/tests/tower/test_client.py +++ b/tests/tower/test_client.py @@ -50,6 +50,7 @@ def _create_run_response( "number": number, "run_id": run_id, "scheduled_at": "2025-04-25T20:54:58.761867Z", + "starting_at": "2025-04-25T20:54:59.366937Z", "started_at": "2025-04-25T20:54:59.366937Z", "status": status, "exit_code": None, @@ -100,6 +101,7 @@ def _create_run( number=number, run_id=run_id, scheduled_at="2025-04-25T20:54:58.761867Z", + starting_at="2025-04-25T20:54:59.366937Z", started_at="2025-04-25T20:54:59.366937Z", status=status, status_group=status_group, diff --git a/uv.lock b/uv.lock index 7f1540e4..05fcc6ee 100644 --- a/uv.lock +++ b/uv.lock @@ -2642,7 +2642,7 @@ wheels = [ [[package]] name = "tower" -version = "0.3.61" +version = "0.3.62" source = { editable = "." } dependencies = [ { name = "attrs" },