Skip to content

Commit

Permalink
Client split (#525)
Browse files Browse the repository at this point in the history
* Rebase

Update codegen code

wip

wip

* Fix doc build

* stripe_* to async-stripe-* crate naming

* Reexport async-stripe-std from root

* Add updated workflow
  • Loading branch information
mzeitlin11 authored Jul 24, 2024
1 parent ba6f20d commit aa89448
Show file tree
Hide file tree
Showing 1,409 changed files with 87,209 additions and 30,145 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ body:
id: language-version
attributes:
label: Rust version
placeholder: Our MSRV is 1.73.0
placeholder: Our MSRV is 1.75.0
validations:
required: true
- type: input
Expand Down
76 changes: 44 additions & 32 deletions .github/workflows/async-stripe.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:

env:
RUSTFLAGS: -Dwarnings
rust_min: 1.73
rust_min: 1.75

jobs:
format:
Expand Down Expand Up @@ -74,16 +74,14 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
runtime:
features:
[
default-tls,
rustls-tls-webpki-roots,
rustls-tls-native,
async-std-surf,
tokio-hyper,
tokio-hyper-rustls,
tokio-hyper-rustls-webpki,
blocking,
blocking-rustls,
blocking-rustls-webpki,
]

steps:
- name: Checkout sources
uses: actions/checkout@v3
Expand All @@ -97,21 +95,46 @@ jobs:
- uses: Swatinem/rust-cache@v2

- name: Run clippy
run: cargo clippy --features "runtime-${{ matrix.runtime }} full serialize deserialize"
run: cargo clippy --no-default-features --features "full serialize deserialize ${{ matrix.features }}"

test:
test-clients:
name: Test Clients
runs-on: ubuntu-latest
strategy:
matrix:
runtime:
features:
[
default-tls,
rustls-tls-webpki-roots,
rustls-tls-native,
async-std-surf,
tokio-hyper,
tokio-hyper-rustls,
tokio-hyper-rustls-webpki,
blocking,
blocking-rustls,
blocking-rustls-webpki,
]

steps:
- name: Checkout sources
uses: actions/checkout@v3

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.rust_min }}
components: clippy

- uses: Swatinem/rust-cache@v2

- name: Run tests
run: cargo test --no-default-features --features "full serialize deserialize ${{ matrix.features }}"

stripe-mock-tests:
name: Stripe Mock Tests
runs-on: ubuntu-latest
strategy:
matrix:
features:
[
default-tls,
rustls-tls-webpki-roots,
rustls-tls-native,
]
services:
stripe-mock:
Expand All @@ -128,20 +151,9 @@ jobs:
toolchain: ${{ env.rust_min }}

- uses: Swatinem/rust-cache@v2
- name: Run stripe mock tests
run: cargo test -p async-stripe-tests --no-default-features --features ${{ matrix.features }}

- uses: taiki-e/install-action@cargo-llvm-cov
- name: Test and gather coverage
run: cargo llvm-cov --lcov --output-path lcov.info --features "runtime-${{ matrix.runtime }} serialize deserialize"
- name: Upload to codecov.io
uses: codecov/[email protected]
with:
token: ${{secrets.CODECOV_TOKEN}}
files: lcov.info
- name: Archive code coverage results
uses: actions/upload-artifact@v1
with:
name: code-coverage-report
path: lcov.info

docs:
name: Docs
Expand All @@ -155,7 +167,7 @@ jobs:
- uses: Swatinem/rust-cache@v2

- name: Build Documentation
run: cargo doc --lib --no-deps --features "runtime-tokio-hyper full"
run: cargo doc --lib --no-deps --features "full serialize deserialize"

# Examples tested separately so that we can use crates which don't match our MSRV
examples:
Expand All @@ -170,4 +182,4 @@ jobs:
- uses: Swatinem/rust-cache@v2

- name: Check examples
run: cargo clippy --features "runtime-tokio-hyper-rustls" --workspace
run: cargo clippy --workspace
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ to run `cargo fmt` to make sure it conforms to the standard.
This library is (mostly) authored via code generation by parsing the OpenAPI specification for Stripe.
It consists of 3 main pieces:
- `async-stripe`: The definition of the `Stripe` client
- `stripe_types`: Core type definitions, used a ton in generated code
- `async-stripe-types`: Core type definitions, used a ton in generated code
- `generated/*`: Generated crates which implement `Stripe` API requests and related types.
- `stripe_webhook`: Glue code for parsing and validating `Stripe` webhook events and generated
- `async-stripe-webhook`: Glue code for parsing and validating `Stripe` webhook events and generated
code for deserializing the events themselves.

No changes should be made to code in a `generated/*` folder. If you'd like to change that
Expand Down
17 changes: 9 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
[workspace]
members = [
"async-stripe",
"stripe_types",
"stripe_webhook",
"async-stripe-types",
"async-stripe-webhook",
"tests",
"generated/*",
"examples/*",
"async-stripe-client-core",
"async-stripe",
]

# Skip "examples/*" when running default commands since that adds a bunch of deps that makes
# development feedback loop slower
default-members = ["async-stripe", "stripe_types", "stripe_webhook", "tests", "generated/*"]
# development feedback loop slower.
default-members = ["async-stripe", "async-stripe-types", "async-stripe-webhook", "async-stripe-client-core", "generated/*"]
resolver = "2"
# Makes dependency management simpler to allow codegen crate to use whichever dep versions
# it wants without affecting dependency resolution of the user-facing library crates
Expand All @@ -19,7 +20,7 @@ exclude = ["openapi"]
[workspace.package]
version = "0.22.2"
description = "API bindings for the Stripe HTTP API"
rust-version = "1.73.0"
rust-version = "1.75.0"
authors = [
"Anna Baldwin <[email protected]>",
"Kevin Stenerson <[email protected]>",
Expand All @@ -37,7 +38,7 @@ edition = "2021"

[workspace.dependencies]
serde = { version = ">=1.0.79", features = ["derive"] } # we use `serde(other)` which was introduced in 1.0.79
serde_json = "1"
http-types = { version = "2.12.0", default-features = false }
smol_str = { version = "0.2.0", features = ["serde"] }
miniserde = "0.1.34"
serde_json = "1.0.115"
serde_qs = "0.12.0"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ If you don't see the specific version you are on, prefer the next available vers

## MSRV

We currently have `1.73.0` pinned in CI, so any version of rustc newer than that should
We currently have `1.75.0` pinned in CI, so any version of rustc newer than that should
work.
If this is not the case, please open an issue. As a policy, we permit MSRV increases in
non-breaking releases.
Expand Down
28 changes: 28 additions & 0 deletions async-stripe-client-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "async-stripe-client-core"
version.workspace = true
description.workspace = true
rust-version.workspace = true
authors.workspace = true
license.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
documentation.workspace = true
keywords.workspace = true
categories.workspace = true
edition.workspace = true

[lib]
name = "stripe_client_core"

[dependencies]
async-stripe-shared = { path = "../generated/async-stripe-shared" }
async-stripe-types = { path = "../async-stripe-types" }
serde_json.workspace = true
serde.workspace = true
serde_qs.workspace = true
bytes = "1.6.0"
miniserde.workspace = true
futures-util = "0.3.28"
uuid = { version = "1.6.1", optional = true, features = ["v4"] }
139 changes: 139 additions & 0 deletions async-stripe-client-core/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use std::fmt;
use std::fmt::{Display, Formatter};

use stripe_shared::version::VERSION;
use stripe_shared::{AccountId, ApiVersion, ApplicationId};

use crate::RequestStrategy;

/// Shared configuration utilities for implementing a Stripe client.
///
/// This is meant for internal use when implementing compatible clients,
/// so it may be more unstable with respect to semver.
// The disclaimer above was written to justify the semver hazard of keeping all the fields here public.
// This is not necessary, but writing accessors is tricky because configs using this
// internally want to take ownership of each field to avoid unnecessary clones.
#[derive(Clone)]
pub struct SharedConfigBuilder {
/// The stripe version being used.
pub stripe_version: ApiVersion,
/// The user-provided part of the user-agent we'll use.
pub app_info_str: Option<String>,
/// The client id to send requests with.
pub client_id: Option<ApplicationId>,
/// The account id to send requests with.
pub account_id: Option<AccountId>,
/// The default request strategy to use.,
pub request_strategy: Option<RequestStrategy>,
/// The secret key for authorizing requests.
pub secret: String,
/// The base URL to send requests to.
pub api_base: Option<String>,
}

impl SharedConfigBuilder {
/// Create a new `SharedConfigBuilder` with the given secret key.
pub fn new(secret: impl Into<String>) -> Self {
Self {
stripe_version: VERSION,
app_info_str: None,
client_id: None,
account_id: None,
request_strategy: None,
secret: secret.into(),
api_base: None,
}
}

/// Set the Stripe client id for the client. This will be sent to stripe
/// with the "client-id" header.
pub fn client_id(mut self, client_id: ApplicationId) -> Self {
self.client_id = Some(client_id);
self
}

/// Set the default Stripe account id used for the client. This will be sent to stripe
/// with the "stripe-account" header, unless it is overridden when customizing
/// a request.
pub fn account_id(mut self, account_id: AccountId) -> Self {
self.account_id = Some(account_id);
self
}

/// Sets the default `RequestStrategy` used when making requests.
pub fn request_strategy(mut self, strategy: RequestStrategy) -> Self {
self.request_strategy = Some(strategy);
self
}

/// Create a new client pointed at a specific URL. This is useful for testing.
pub fn url(mut self, url: impl Into<String>) -> Self {
self.api_base = Some(url.into());
self
}

/// Set the application info for the client.
pub fn app_info(
mut self,
name: impl Into<String>,
version: Option<String>,
url: Option<String>,
) -> Self {
self.app_info_str = Some(AppInfo { name: name.into(), url, version }.to_string());
self
}
}

struct AppInfo {
name: String,
url: Option<String>,
version: Option<String>,
}

impl Display for AppInfo {
/// Formats a plugin's 'App Info' into a string that can be added to the end of a User-Agent string.
///
/// This formatting matches that of other libraries, and if changed then it should be changed everywhere.
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name = &self.name;
match (&self.version, &self.url) {
(Some(a), Some(b)) => write!(f, "{name}/{a} ({b})"),
(Some(a), None) => write!(f, "{name}/{a}"),
(None, Some(b)) => write!(f, "{name} ({b})"),
_ => f.write_str(name),
}
}
}

// Manual implementation so we don't print the secret!
impl fmt::Debug for SharedConfigBuilder {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("SharedConfigBuilder");
builder.field("request_strategy", &self.request_strategy);
builder.field("client_id", &self.client_id);
builder.field("account_id", &self.account_id);
builder.field("app_info_str", &self.app_info_str);
if let Some(api_base) = &self.api_base {
builder.field("api_base", api_base);
}
builder.field("stripe_version", &self.stripe_version);
builder.finish()
}
}

/// Per-request configuration overrides.
#[derive(Debug)]
#[non_exhaustive]
pub struct ConfigOverride {
/// Use a particular account id, instead of the client default.
pub account_id: Option<AccountId>,
/// Use a particular `RequestStrategy`, instead of the client default.
pub request_strategy: Option<RequestStrategy>,
}

impl ConfigOverride {
pub(crate) fn new() -> Self {
Self { account_id: None, request_strategy: None }
}
}
17 changes: 17 additions & 0 deletions async-stripe-client-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! This crate provides shared utilities for implementing clients
//! capable of making Stripe API requests.
#![warn(clippy::missing_errors_doc, clippy::missing_panics_doc)]
#![deny(missing_docs, missing_debug_implementations)]
#![forbid(unsafe_code)]
mod config;
mod pagination;
mod request_strategy;
mod stripe_request;

pub use config::{ConfigOverride, SharedConfigBuilder};
pub use pagination::*;
pub use request_strategy::*;
pub use stripe_request::*;
pub use stripe_shared::version::VERSION;
pub use stripe_shared::{AccountId, ApiVersion, ApplicationId};
Loading

0 comments on commit aa89448

Please sign in to comment.