Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ jobs:
- name: Rust Cache
uses: Swatinem/rust-cache@v2

- name: Test downstream macro dependencies
run: python3 test-macro-dependencies.py
- name: Test standalone consumers
run: python3 test-downstream.py

- name: Test without default features
run: cargo test -p gotcha --no-default-features

- name: Run tests (gotcha_macro)
run: |
Expand Down
11 changes: 11 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Migration Guide

- [Unreleased: HTTP/1 is always enabled](#unreleased-http1-is-always-enabled)
- [Unreleased: derive dependency paths](#unreleased-derive-dependency-paths)
- [Unreleased: explicit OpenAPI endpoints](#unreleased-explicit-openapi-endpoints)
- [Unreleased: message task handles](#unreleased-message-task-handles)
Expand All @@ -19,6 +20,16 @@

---

# Unreleased: HTTP/1 is always enabled

The `http1` feature has been removed. It existed to support Cloudflare Worker integration,
which is no longer supported. HTTP/1 and Tokio support are now required Axum dependency
features, so server startup remains available even with `default-features = false`.

Remove `"http1"` from any explicit gotcha feature lists. Default application behavior is
unchanged; `openapi`, `prometheus`, `cors`, `static_files`, and `task` remain optional.
Libraries that only implement `Schematic` can continue to depend on `gotcha_core` directly.

# Unreleased: derive dependency paths

**`Schematic` stays in `gotcha_core`.** Libraries can continue to depend only on core and either
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ serde = { version = "1", features = ["derive"] }

### Optional Features

HTTP/1 serving is always enabled, including with `default-features = false`.
The builder's `run`/`listen`/`listen_on` and `GotchaApp::run` are always available.

Enable additional features as needed:

```toml
Expand Down
2 changes: 1 addition & 1 deletion examples/configuration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
gotcha = {version="0.4", path = "../../gotcha", features = ["http1"]}
gotcha = {version="0.4", path = "../../gotcha"}
serde = {version="1", features=["derive"]}
serde_json = "1"
tokio = {version = "1", features = ["macros", 'rt-multi-thread', 'fs']}
Expand Down
4 changes: 2 additions & 2 deletions examples/openapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
gotcha = {version="0.4", path = "../../gotcha", features = ["openapi", "http1"]}
gotcha = {version="0.4", path = "../../gotcha", features = ["openapi"]}
# Required because `#[derive(Schematic)]` expands to `::gotcha_core::` paths.
gotcha_core = { path = "../../gotcha_core" }
tokio = {version = "1", features = ["macros", 'rt-multi-thread']}
serde = {version="1", features=["derive"]}
serde_json = "1"
serde_json = "1"
4 changes: 2 additions & 2 deletions examples/task/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
gotcha = {version="0.4", path = "../../gotcha", features = ["task", "http1"]}
gotcha = {version="0.4", path = "../../gotcha", features = ["task"]}
tokio = {version = "1", features = ["macros", 'rt-multi-thread']}
serde = {version="1", features=["derive"]}
serde = {version="1", features=["derive"]}
6 changes: 3 additions & 3 deletions gotcha/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ doctest = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["http1"]
http1 = ["axum/http1", "axum/tokio"]
default = []
prometheus = ["dep:axum-prometheus"]
openapi = ["dep:oas", "dep:gotcha_core", "gotcha_core/axum"]
# These enable only their own half of `tower-http`. That matters: `tower-http/cors` has no
Expand All @@ -49,7 +48,8 @@ cron = {version = "0.12.0", optional = true}
chrono = "0.4.23"
oas = { version = "0.1", optional = true }
mofa = "0.2"
axum = { version = "0.8", default-features = false, features = ["form", "json", "query", "multipart", "ws", "matched-path", "original-uri"] }
# HTTP/1 serving is a required capability, including with default features disabled.
axum = { version = "0.8", default-features = false, features = ["http1", "tokio", "form", "json", "query", "multipart", "ws", "matched-path", "original-uri"] }
# For `TypedHeader<T>`: axum 0.7 moved it out of axum proper. Only the `typed-header` feature is
# enabled, which brings in the `headers` crate and nothing else.
axum-extra = { version = "0.10", default-features = false, features = ["typed-header"] }
Expand Down
8 changes: 7 additions & 1 deletion test-macro-dependencies.py → test-downstream.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Test derives in standalone Cargo projects without workspace dev-dependencies."""
"""Test standalone consumers without workspace dependency feature unification."""

import os
from pathlib import Path
Expand All @@ -26,6 +26,12 @@ def main():
if unexpected:
raise RuntimeError(f"{name} pulled in web dependencies: {sorted(unexpected)}")

manifest = str(root / "tests" / "fixtures" / "no-default-features" / "Cargo.toml")
subprocess.run(["cargo", "fmt", "--manifest-path", manifest, "--", "--check"], check=True, env=env)
for features in ([], ["--features", "openapi"]):
print(f"Checking startup without default features: {features}", flush=True)
subprocess.run(["cargo", "check", "--manifest-path", manifest, *features], check=True, env=env)


if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions test-feature-matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ def load_features():
in_features = False
elif in_features and "=" in stripped and not stripped.startswith("#"):
feature = stripped.split("=")[0].strip()
# `default` is implied, and `http1` is part of it rather than something to toggle.
if feature not in ("default", "http1"):
# Cargo enables the default group automatically; test the optional features.
if feature != "default":
features.append(feature)
return features

Expand Down
13 changes: 13 additions & 0 deletions tests/fixtures/no-default-features/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "no-default-features"
version = "0.0.0"
edition = "2021"
publish = false

[workspace]

[features]
openapi = ["gotcha/openapi"]

[dependencies]
gotcha = { path = "../../../gotcha", default-features = false }
24 changes: 24 additions & 0 deletions tests/fixtures/no-default-features/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use gotcha::{ConfigWrapper, EmptyConfig, Gotcha, GotchaApp, GotchaContext, GotchaResult, GotchaRouter};

struct App;

impl GotchaApp for App {
type State = ();
type Config = EmptyConfig;

async fn state(&self, _: &ConfigWrapper<EmptyConfig>) -> GotchaResult<()> {
Ok(())
}

fn routes(&self, router: GotchaRouter<GotchaContext<(), EmptyConfig>>) -> GotchaRouter<GotchaContext<(), EmptyConfig>> {
router
}
}

fn main() {
// All startup entry points must compile without relying on workspace feature unification.
drop(Gotcha::new().run());
drop(Gotcha::new().listen("127.0.0.1:0"));
drop(Gotcha::new().listen_on("127.0.0.1:0".parse().unwrap()));
drop(App.run());
}
Loading