mirror of https://github.com/smithy-lang/smithy-rs
Allow User Agent to accept business metrics (#3781)
## Motivation and Context This PR lays the groundwork for emitting and tracking business metrics related to features like waiters, request compression, and S3 express within the Rust SDKs. It introduces `BusinessMetric` to the `user_agent` module and updates `AwsUserAgent` to support its integration. ## Description While establishing the groundwork for the said motivation, this PR does not send metrics from features yet. The PR deprecates existing feature and config metadata, which are now superseded by the new business metrics. Related tasks include - implementing versioning for the user agent string format, e.g. `ua/2.0` (note that including a user agent version string to `x-amz-user-agent` could cause many connection recording tests to fail and may also break semver check in CI just like the [content-length enforcement test](https://github.com/smithy-lang/smithy-rs/pull/3620) needed to be disabled to work around it) - sending metrics from recently implement features, maybe starting with request compression and RPC V2 Cbor (this will also modify `x-amz-user-agent` in connection recording tests, so the argument above applies) ## Testing - Added unit tests for `BusinessMetric` and `AwsUserAgent` - Existing tests in CI ## Checklist - [x] For changes to the AWS SDK, generated SDK code, or SDK runtime crates, I have created a changelog entry Markdown file in the `.changelog` directory, specifying "aws-sdk-rust" in the `applies_to` key. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
This commit is contained in:
parent
bb1971a1ba
commit
c0f817330c
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
applies_to:
|
||||
- aws-sdk-rust
|
||||
authors:
|
||||
- ysaito1001
|
||||
references:
|
||||
- smithy-rs#3781
|
||||
breaking: false
|
||||
new_feature: false
|
||||
bug_fix: false
|
||||
---
|
||||
Allow [AwsUserAgent](https://docs.rs/aws-runtime/1.3.1/aws_runtime/user_agent/struct.AwsUserAgent.html) to incorporate business metrics, which now deprecates the existing feature and config metadata.
|
|
@ -108,7 +108,7 @@ version = "0.60.3"
|
|||
|
||||
[[package]]
|
||||
name = "aws-http"
|
||||
version = "0.60.5"
|
||||
version = "0.60.6"
|
||||
dependencies = [
|
||||
"aws-runtime",
|
||||
]
|
||||
|
@ -149,7 +149,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "aws-runtime"
|
||||
version = "1.3.1"
|
||||
version = "1.4.0"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"aws-credential-types",
|
||||
|
@ -163,12 +163,14 @@ dependencies = [
|
|||
"aws-types",
|
||||
"bytes",
|
||||
"bytes-utils",
|
||||
"convert_case",
|
||||
"fastrand",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"http 1.1.0",
|
||||
"http-body 0.4.6",
|
||||
"http-body 1.0.0",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"proptest",
|
||||
|
@ -282,21 +284,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "aws-smithy-protocol-test"
|
||||
version = "0.60.7"
|
||||
version = "0.62.0"
|
||||
dependencies = [
|
||||
"assert-json-diff",
|
||||
"aws-smithy-runtime-api",
|
||||
"base64-simd",
|
||||
"cbor-diag",
|
||||
"http 0.2.12",
|
||||
"pretty_assertions",
|
||||
"regex-lite",
|
||||
"roxmltree",
|
||||
"serde_cbor",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-runtime"
|
||||
version = "1.6.1"
|
||||
version = "1.6.2"
|
||||
dependencies = [
|
||||
"aws-smithy-async",
|
||||
"aws-smithy-http",
|
||||
|
@ -449,6 +454,15 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
|
@ -477,6 +491,25 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cbor-diag"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc245b6ecd09b23901a4fbad1ad975701fd5061ceaef6afa93a2d70605a64429"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"chrono",
|
||||
"data-encoding",
|
||||
"half 2.4.1",
|
||||
"nom",
|
||||
"num-bigint",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"separator",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.99"
|
||||
|
@ -494,6 +527,15 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.2"
|
||||
|
@ -518,7 +560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
"half 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -552,6 +594,15 @@ version = "0.9.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
|
@ -694,6 +745,12 @@ dependencies = [
|
|||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.6.1"
|
||||
|
@ -923,6 +980,12 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.4.1"
|
||||
|
@ -1079,6 +1142,16 @@ dependencies = [
|
|||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.6"
|
||||
|
@ -1218,6 +1291,12 @@ version = "2.7.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
|
@ -1238,6 +1317,16 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
|
@ -1248,6 +1337,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
|
@ -1263,6 +1362,17 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
|
@ -1821,6 +1931,12 @@ version = "1.0.23"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||
|
||||
[[package]]
|
||||
name = "separator"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
|
@ -1830,6 +1946,16 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_cbor"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
|
||||
dependencies = [
|
||||
"half 1.8.3",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
|
@ -2053,6 +2179,21 @@ dependencies = [
|
|||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
|
||||
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 = "tokio"
|
||||
version = "1.38.0"
|
||||
|
@ -2212,18 +2353,50 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.8.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "aws-http"
|
||||
version = "0.60.5"
|
||||
version = "0.60.6"
|
||||
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "Russell Cohen <rcoh@amazon.com>"]
|
||||
description = "This crate is no longer used by the AWS SDK and is deprecated."
|
||||
edition = "2021"
|
||||
|
|
|
@ -31,18 +31,20 @@ pub type InvalidMetadataValue = aws_runtime::user_agent::InvalidMetadataValue;
|
|||
)]
|
||||
pub type AdditionalMetadata = aws_runtime::user_agent::AdditionalMetadata;
|
||||
|
||||
/// Use aws_runtime::user_agent::FeatureMetadata instead.
|
||||
/// Use aws_runtime::user_agent::BusinessMetric instead.
|
||||
#[deprecated(
|
||||
since = "0.60.2",
|
||||
note = "Use aws_runtime::user_agent::FeatureMetadata instead."
|
||||
note = "Use aws_runtime::user_agent::BusinessMetric instead."
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub type FeatureMetadata = aws_runtime::user_agent::FeatureMetadata;
|
||||
|
||||
/// Use aws_runtime::user_agent::ConfigMetadata instead.
|
||||
/// Use aws_runtime::user_agent::BusinessMetric instead.
|
||||
#[deprecated(
|
||||
since = "0.60.2",
|
||||
note = "Use aws_runtime::user_agent::ConfigMetadata instead."
|
||||
note = "Use aws_runtime::user_agent::BusinessMetric instead."
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub type ConfigMetadata = aws_runtime::user_agent::ConfigMetadata;
|
||||
|
||||
/// Use aws_runtime::user_agent::FrameworkMetadata instead.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "aws-runtime"
|
||||
version = "1.3.1"
|
||||
version = "1.4.0"
|
||||
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
|
||||
description = "Runtime support code for the AWS SDK. This crate isn't intended to be used directly."
|
||||
edition = "2021"
|
||||
|
@ -30,6 +30,7 @@ http-02x = { package = "http", version = "0.2.3" }
|
|||
http-body-04x = { package = "http-body", version = "0.4.5" }
|
||||
http-1x = { package = "http", version = "1.1.0", optional = true }
|
||||
http-body-1x = { package = "http-body", version = "1.0.0", optional = true }
|
||||
once_cell = "1.18.0"
|
||||
percent-encoding = "2.1.0"
|
||||
pin-project-lite = "0.2.9"
|
||||
tracing = "0.1"
|
||||
|
@ -43,6 +44,7 @@ aws-smithy-protocol-test = { path = "../../../rust-runtime/aws-smithy-protocol-t
|
|||
aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api", features = ["test-util"] }
|
||||
aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types", features = ["test-util"] }
|
||||
bytes-utils = "0.1.2"
|
||||
convert_case = "0.6.0"
|
||||
futures-util = { version = "0.3.29", default-features = false }
|
||||
proptest = "1.2"
|
||||
serde = { version = "1", features = ["derive"]}
|
||||
|
|
|
@ -12,8 +12,11 @@ use std::error::Error;
|
|||
use std::fmt;
|
||||
|
||||
mod interceptor;
|
||||
mod metrics;
|
||||
|
||||
use crate::user_agent::metrics::BusinessMetrics;
|
||||
pub use interceptor::UserAgentInterceptor;
|
||||
pub use metrics::BusinessMetric;
|
||||
|
||||
/// AWS User Agent
|
||||
///
|
||||
|
@ -27,8 +30,7 @@ pub struct AwsUserAgent {
|
|||
os_metadata: OsMetadata,
|
||||
language_metadata: LanguageMetadata,
|
||||
exec_env_metadata: Option<ExecEnvMetadata>,
|
||||
feature_metadata: Vec<FeatureMetadata>,
|
||||
config_metadata: Vec<ConfigMetadata>,
|
||||
business_metrics: BusinessMetrics,
|
||||
framework_metadata: Vec<FrameworkMetadata>,
|
||||
app_name: Option<AppName>,
|
||||
build_env_additional_metadata: Option<AdditionalMetadata>,
|
||||
|
@ -70,9 +72,8 @@ impl AwsUserAgent {
|
|||
extras: Default::default(),
|
||||
},
|
||||
exec_env_metadata,
|
||||
feature_metadata: Default::default(),
|
||||
config_metadata: Default::default(),
|
||||
framework_metadata: Default::default(),
|
||||
business_metrics: Default::default(),
|
||||
app_name: Default::default(),
|
||||
build_env_additional_metadata,
|
||||
additional_metadata: Default::default(),
|
||||
|
@ -102,8 +103,7 @@ impl AwsUserAgent {
|
|||
extras: Default::default(),
|
||||
},
|
||||
exec_env_metadata: None,
|
||||
feature_metadata: Vec::new(),
|
||||
config_metadata: Vec::new(),
|
||||
business_metrics: Default::default(),
|
||||
framework_metadata: Vec::new(),
|
||||
app_name: None,
|
||||
build_env_additional_metadata: None,
|
||||
|
@ -111,31 +111,65 @@ impl AwsUserAgent {
|
|||
}
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.4.0",
|
||||
note = "This is a no-op; use `with_business_metric` instead."
|
||||
)]
|
||||
#[allow(unused_mut)]
|
||||
#[allow(deprecated)]
|
||||
#[doc(hidden)]
|
||||
/// Adds feature metadata to the user agent.
|
||||
pub fn with_feature_metadata(mut self, metadata: FeatureMetadata) -> Self {
|
||||
self.feature_metadata.push(metadata);
|
||||
pub fn with_feature_metadata(mut self, _metadata: FeatureMetadata) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.4.0",
|
||||
note = "This is a no-op; use `add_business_metric` instead."
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
#[allow(unused_mut)]
|
||||
#[doc(hidden)]
|
||||
/// Adds feature metadata to the user agent.
|
||||
pub fn add_feature_metadata(&mut self, metadata: FeatureMetadata) -> &mut Self {
|
||||
self.feature_metadata.push(metadata);
|
||||
pub fn add_feature_metadata(&mut self, _metadata: FeatureMetadata) -> &mut Self {
|
||||
self
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.4.0",
|
||||
note = "This is a no-op; use `with_business_metric` instead."
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
#[allow(unused_mut)]
|
||||
#[doc(hidden)]
|
||||
/// Adds config metadata to the user agent.
|
||||
pub fn with_config_metadata(mut self, _metadata: ConfigMetadata) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.4.0",
|
||||
note = "This is a no-op; use `add_business_metric` instead."
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
#[allow(unused_mut)]
|
||||
#[doc(hidden)]
|
||||
/// Adds config metadata to the user agent.
|
||||
pub fn add_config_metadata(&mut self, _metadata: ConfigMetadata) -> &mut Self {
|
||||
self
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Adds config metadata to the user agent.
|
||||
pub fn with_config_metadata(mut self, metadata: ConfigMetadata) -> Self {
|
||||
self.config_metadata.push(metadata);
|
||||
/// Adds business metric to the user agent.
|
||||
pub fn with_business_metric(mut self, metric: BusinessMetric) -> Self {
|
||||
self.business_metrics.push(metric);
|
||||
self
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Adds config metadata to the user agent.
|
||||
pub fn add_config_metadata(&mut self, metadata: ConfigMetadata) -> &mut Self {
|
||||
self.config_metadata.push(metadata);
|
||||
/// Adds business metric to the user agent.
|
||||
pub fn add_business_metric(&mut self, metric: BusinessMetric) -> &mut Self {
|
||||
self.business_metrics.push(metric);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -188,10 +222,10 @@ impl AwsUserAgent {
|
|||
os-metadata RWS
|
||||
language-metadata RWS
|
||||
[env-metadata RWS]
|
||||
*(feat-metadata RWS)
|
||||
*(config-metadata RWS)
|
||||
*(framework-metadata RWS)
|
||||
; ordering is not strictly required in the following section
|
||||
[business-metrics]
|
||||
[appId]
|
||||
*(framework-metadata RWS)
|
||||
*/
|
||||
let mut ua_value = String::new();
|
||||
use std::fmt::Write;
|
||||
|
@ -203,11 +237,8 @@ impl AwsUserAgent {
|
|||
if let Some(ref env_meta) = self.exec_env_metadata {
|
||||
write!(ua_value, "{} ", env_meta).unwrap();
|
||||
}
|
||||
for feature in &self.feature_metadata {
|
||||
write!(ua_value, "{} ", feature).unwrap();
|
||||
}
|
||||
for config in &self.config_metadata {
|
||||
write!(ua_value, "{} ", config).unwrap();
|
||||
if !self.business_metrics.is_empty() {
|
||||
write!(ua_value, "{} ", &self.business_metrics).unwrap()
|
||||
}
|
||||
for framework in &self.framework_metadata {
|
||||
write!(ua_value, "{} ", framework).unwrap();
|
||||
|
@ -370,6 +401,7 @@ impl fmt::Display for AdditionalMetadataList {
|
|||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.4.0", note = "Replaced by `BusinessMetric`.")]
|
||||
#[doc(hidden)]
|
||||
/// Metadata about a feature that is being used in the SDK.
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -380,6 +412,7 @@ pub struct FeatureMetadata {
|
|||
additional: AdditionalMetadataList,
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl FeatureMetadata {
|
||||
/// Creates `FeatureMetadata`.
|
||||
///
|
||||
|
@ -406,6 +439,7 @@ impl FeatureMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl fmt::Display for FeatureMetadata {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// feat-metadata = "ft/" name ["/" version] *(RWS additional-metadata)
|
||||
|
@ -417,6 +451,7 @@ impl fmt::Display for FeatureMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.4.0", note = "Replaced by `BusinessMetric`.")]
|
||||
#[doc(hidden)]
|
||||
/// Metadata about a config value that is being used in the SDK.
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -426,6 +461,7 @@ pub struct ConfigMetadata {
|
|||
value: Option<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl ConfigMetadata {
|
||||
/// Creates `ConfigMetadata`.
|
||||
///
|
||||
|
@ -445,6 +481,7 @@ impl ConfigMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl fmt::Display for ConfigMetadata {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// config-metadata = "cfg/" config ["/" value]
|
||||
|
@ -605,54 +642,6 @@ mod test {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_a_valid_ua_with_features() {
|
||||
let api_metadata = ApiMetadata {
|
||||
service_id: "dynamodb".into(),
|
||||
version: "123",
|
||||
};
|
||||
let mut ua = AwsUserAgent::new_from_environment(Env::from_slice(&[]), api_metadata)
|
||||
.with_feature_metadata(
|
||||
FeatureMetadata::new("test-feature", Some(Cow::Borrowed("1.0"))).unwrap(),
|
||||
)
|
||||
.with_feature_metadata(
|
||||
FeatureMetadata::new("other-feature", None)
|
||||
.unwrap()
|
||||
.with_additional(AdditionalMetadata::new("asdf").unwrap()),
|
||||
);
|
||||
make_deterministic(&mut ua);
|
||||
assert_eq!(
|
||||
ua.aws_ua_header(),
|
||||
"aws-sdk-rust/0.1 api/dynamodb/123 os/macos/1.15 lang/rust/1.50.0 ft/test-feature/1.0 ft/other-feature md/asdf"
|
||||
);
|
||||
assert_eq!(
|
||||
ua.ua_header(),
|
||||
"aws-sdk-rust/0.1 os/macos/1.15 lang/rust/1.50.0"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_a_valid_ua_with_config() {
|
||||
let api_metadata = ApiMetadata {
|
||||
service_id: "dynamodb".into(),
|
||||
version: "123",
|
||||
};
|
||||
let mut ua = AwsUserAgent::new_from_environment(Env::from_slice(&[]), api_metadata)
|
||||
.with_config_metadata(
|
||||
ConfigMetadata::new("some-config", Some(Cow::Borrowed("5"))).unwrap(),
|
||||
)
|
||||
.with_config_metadata(ConfigMetadata::new("other-config", None).unwrap());
|
||||
make_deterministic(&mut ua);
|
||||
assert_eq!(
|
||||
ua.aws_ua_header(),
|
||||
"aws-sdk-rust/0.1 api/dynamodb/123 os/macos/1.15 lang/rust/1.50.0 cfg/some-config/5 cfg/other-config"
|
||||
);
|
||||
assert_eq!(
|
||||
ua.ua_header(),
|
||||
"aws-sdk-rust/0.1 os/macos/1.15 lang/rust/1.50.0"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_a_valid_ua_with_frameworks() {
|
||||
let api_metadata = ApiMetadata {
|
||||
|
@ -709,6 +698,37 @@ mod test {
|
|||
"aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_a_valid_ua_with_business_metrics() {
|
||||
// single metric ID
|
||||
{
|
||||
let ua = AwsUserAgent::for_tests().with_business_metric(BusinessMetric::ResourceModel);
|
||||
assert_eq!(
|
||||
ua.aws_ua_header(),
|
||||
"aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0 m/A"
|
||||
);
|
||||
assert_eq!(
|
||||
ua.ua_header(),
|
||||
"aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0"
|
||||
);
|
||||
}
|
||||
// multiple metric IDs
|
||||
{
|
||||
let ua = AwsUserAgent::for_tests()
|
||||
.with_business_metric(BusinessMetric::RetryModeAdaptive)
|
||||
.with_business_metric(BusinessMetric::S3Transfer)
|
||||
.with_business_metric(BusinessMetric::S3ExpressBucket);
|
||||
assert_eq!(
|
||||
ua.aws_ua_header(),
|
||||
"aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0 m/F,G,J"
|
||||
);
|
||||
assert_eq!(
|
||||
ua.ua_header(),
|
||||
"aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -729,21 +749,25 @@ api-metadata = "api/" service-id "/" version
|
|||
os-metadata = "os/" os-family ["/" version]
|
||||
language-metadata = "lang/" language "/" version *(RWS additional-metadata)
|
||||
env-metadata = "exec-env/" name
|
||||
feat-metadata = "ft/" name ["/" version] *(RWS additional-metadata)
|
||||
config-metadata = "cfg/" config ["/" value]
|
||||
framework-metadata = "lib/" name ["/" version] *(RWS additional-metadata)
|
||||
app-id = "app/" name
|
||||
build-env-additional-metadata = "md/" value
|
||||
ua-metadata = "ua/2.1"
|
||||
business-metrics = "m/" metric_id *(comma metric_id)
|
||||
metric_id = 1*m_char
|
||||
m_char = DIGIT / ALPHA / "+" / "-"
|
||||
comma = ","
|
||||
ua-string = sdk-metadata RWS
|
||||
ua-metadata RWS
|
||||
[api-metadata RWS]
|
||||
os-metadata RWS
|
||||
language-metadata RWS
|
||||
[env-metadata RWS]
|
||||
*(feat-metadata RWS)
|
||||
*(config-metadata RWS)
|
||||
*(framework-metadata RWS)
|
||||
; ordering is not strictly required in the following section
|
||||
[business-metrics]
|
||||
[app-id]
|
||||
[build-env-additional-metadata]
|
||||
*(framework-metadata RWS)
|
||||
|
||||
# New metadata field might be added in the future and they must follow this format
|
||||
prefix = token
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
const MAX_COMMA_SEPARATED_METRICS_VALUES_LENGTH: usize = 1024;
|
||||
#[allow(dead_code)]
|
||||
const MAX_METRICS_ID_NUMBER: usize = 350;
|
||||
|
||||
macro_rules! iterable_enum {
|
||||
($docs:tt, $enum_name:ident, $( $variant:ident ),*) => {
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
#[doc = $docs]
|
||||
#[allow(missing_docs)] // for variants, not for the Enum itself
|
||||
pub enum $enum_name {
|
||||
$( $variant ),*
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl $enum_name {
|
||||
pub(crate) fn iter() -> impl Iterator<Item = &'static $enum_name> {
|
||||
const VARIANTS: &[$enum_name] = &[
|
||||
$( $enum_name::$variant ),*
|
||||
];
|
||||
VARIANTS.iter()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct Base64Iterator {
|
||||
current: Vec<usize>,
|
||||
base64_chars: Vec<char>,
|
||||
}
|
||||
|
||||
impl Base64Iterator {
|
||||
#[allow(dead_code)]
|
||||
fn new() -> Self {
|
||||
Base64Iterator {
|
||||
current: vec![0], // Start with the first character
|
||||
base64_chars: (b'A'..=b'Z') // 'A'-'Z'
|
||||
.chain(b'a'..=b'z') // 'a'-'z'
|
||||
.chain(b'0'..=b'9') // '0'-'9'
|
||||
.chain([b'+', b'-']) // '+' and '-'
|
||||
.map(|c| c as char)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn increment(&mut self) {
|
||||
let mut i = 0;
|
||||
while i < self.current.len() {
|
||||
self.current[i] += 1;
|
||||
if self.current[i] < self.base64_chars.len() {
|
||||
// The value at current position hasn't reached 64
|
||||
return;
|
||||
}
|
||||
self.current[i] = 0;
|
||||
i += 1;
|
||||
}
|
||||
self.current.push(0); // Add new digit if all positions overflowed
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Base64Iterator {
|
||||
type Item = String;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current.is_empty() {
|
||||
return None; // No more items
|
||||
}
|
||||
|
||||
// Convert the current indices to characters
|
||||
let result: String = self
|
||||
.current
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|&idx| self.base64_chars[idx])
|
||||
.collect();
|
||||
|
||||
// Increment to the next value
|
||||
self.increment();
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) static FEATURE_ID_TO_METRIC_VALUE: Lazy<HashMap<BusinessMetric, Cow<'static, str>>> =
|
||||
Lazy::new(|| {
|
||||
let mut m = HashMap::new();
|
||||
for (metric, value) in BusinessMetric::iter()
|
||||
.cloned()
|
||||
.zip(Base64Iterator::new())
|
||||
.take(MAX_METRICS_ID_NUMBER)
|
||||
{
|
||||
m.insert(metric, Cow::Owned(value));
|
||||
}
|
||||
m
|
||||
});
|
||||
|
||||
iterable_enum!(
|
||||
"Enumerates human readable identifiers for the features tracked by metrics",
|
||||
BusinessMetric,
|
||||
ResourceModel,
|
||||
Waiter,
|
||||
Paginator,
|
||||
RetryModeLegacy,
|
||||
RetryModeStandard,
|
||||
RetryModeAdaptive,
|
||||
S3Transfer,
|
||||
S3CryptoV1n,
|
||||
S3CryptoV2,
|
||||
S3ExpressBucket,
|
||||
S3AccessGrants,
|
||||
GzipRequestCompression,
|
||||
ProtocolRpcV2Cbor,
|
||||
EndpointOverride,
|
||||
AccountIdEndpoint,
|
||||
AccountIdModePreferred,
|
||||
AccountIdModeDisabled,
|
||||
AccountIdModeRequired,
|
||||
Sigv4aSigning,
|
||||
ResolvedAccountId
|
||||
);
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(super) struct BusinessMetrics(Vec<BusinessMetric>);
|
||||
|
||||
impl BusinessMetrics {
|
||||
pub(super) fn push(&mut self, metric: BusinessMetric) {
|
||||
self.0.push(metric);
|
||||
}
|
||||
|
||||
pub(super) fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_unfinished_metrics_to_fit(csv: &str, max_len: usize) -> Cow<'_, str> {
|
||||
if csv.len() <= max_len {
|
||||
Cow::Borrowed(csv)
|
||||
} else {
|
||||
let truncated = &csv[..max_len];
|
||||
if let Some(pos) = truncated.rfind(',') {
|
||||
Cow::Owned(truncated[..pos].to_owned())
|
||||
} else {
|
||||
Cow::Owned(truncated.to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BusinessMetrics {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// business-metrics = "m/" metric_id *(comma metric_id)
|
||||
let metrics_values = self
|
||||
.0
|
||||
.iter()
|
||||
.map(|feature_id| {
|
||||
FEATURE_ID_TO_METRIC_VALUE
|
||||
.get(feature_id)
|
||||
.expect("{feature_id:?} should be found in `FEATURE_ID_TO_METRIC_VALUE`")
|
||||
.clone()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
|
||||
let metrics_values = drop_unfinished_metrics_to_fit(
|
||||
&metrics_values,
|
||||
MAX_COMMA_SEPARATED_METRICS_VALUES_LENGTH,
|
||||
);
|
||||
|
||||
write!(f, "m/{}", metrics_values)
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::user_agent::metrics::{
|
||||
drop_unfinished_metrics_to_fit, Base64Iterator, FEATURE_ID_TO_METRIC_VALUE,
|
||||
MAX_METRICS_ID_NUMBER,
|
||||
};
|
||||
use crate::user_agent::BusinessMetric;
|
||||
use convert_case::{Boundary, Case, Casing};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
impl Display for BusinessMetric {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(
|
||||
&format!("{:?}", self)
|
||||
.as_str()
|
||||
.from_case(Case::Pascal)
|
||||
.with_boundaries(&[Boundary::DigitUpper, Boundary::LowerUpper])
|
||||
.to_case(Case::ScreamingSnake),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn feature_id_to_metric_value() {
|
||||
const EXPECTED: &str = r#"
|
||||
{
|
||||
"RESOURCE_MODEL": "A",
|
||||
"WAITER": "B",
|
||||
"PAGINATOR": "C",
|
||||
"RETRY_MODE_LEGACY": "D",
|
||||
"RETRY_MODE_STANDARD": "E",
|
||||
"RETRY_MODE_ADAPTIVE": "F",
|
||||
"S3_TRANSFER": "G",
|
||||
"S3_CRYPTO_V1N": "H",
|
||||
"S3_CRYPTO_V2": "I",
|
||||
"S3_EXPRESS_BUCKET": "J",
|
||||
"S3_ACCESS_GRANTS": "K",
|
||||
"GZIP_REQUEST_COMPRESSION": "L",
|
||||
"PROTOCOL_RPC_V2_CBOR": "M",
|
||||
"ENDPOINT_OVERRIDE": "N",
|
||||
"ACCOUNT_ID_ENDPOINT": "O",
|
||||
"ACCOUNT_ID_MODE_PREFERRED": "P",
|
||||
"ACCOUNT_ID_MODE_DISABLED": "Q",
|
||||
"ACCOUNT_ID_MODE_REQUIRED": "R",
|
||||
"SIGV4A_SIGNING": "S",
|
||||
"RESOLVED_ACCOUNT_ID": "T"
|
||||
}
|
||||
"#;
|
||||
|
||||
let expected: HashMap<&str, &str> = serde_json::from_str(EXPECTED).unwrap();
|
||||
assert_eq!(expected.len(), FEATURE_ID_TO_METRIC_VALUE.len());
|
||||
|
||||
for (feature_id, metric_value) in &*FEATURE_ID_TO_METRIC_VALUE {
|
||||
assert_eq!(
|
||||
expected.get(format!("{feature_id}").as_str()).unwrap(),
|
||||
metric_value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base64_iter() {
|
||||
// 350 is the max number of metric IDs we support for now
|
||||
let ids: Vec<String> = Base64Iterator::new()
|
||||
.into_iter()
|
||||
.take(MAX_METRICS_ID_NUMBER)
|
||||
.collect();
|
||||
assert_eq!("A", ids[0]);
|
||||
assert_eq!("Z", ids[25]);
|
||||
assert_eq!("a", ids[26]);
|
||||
assert_eq!("z", ids[51]);
|
||||
assert_eq!("0", ids[52]);
|
||||
assert_eq!("9", ids[61]);
|
||||
assert_eq!("+", ids[62]);
|
||||
assert_eq!("-", ids[63]);
|
||||
assert_eq!("AA", ids[64]);
|
||||
assert_eq!("AB", ids[65]);
|
||||
assert_eq!("A-", ids[127]);
|
||||
assert_eq!("BA", ids[128]);
|
||||
assert_eq!("Ed", ids[349]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop_unfinished_metrics_to_fit() {
|
||||
let csv = "A,10BC,E";
|
||||
assert_eq!("A", drop_unfinished_metrics_to_fit(csv, 5));
|
||||
|
||||
let csv = "A10B,CE";
|
||||
assert_eq!("A10B", drop_unfinished_metrics_to_fit(csv, 5));
|
||||
|
||||
let csv = "A10BC,E";
|
||||
assert_eq!("A10BC", drop_unfinished_metrics_to_fit(csv, 5));
|
||||
|
||||
let csv = "A10BCE";
|
||||
assert_eq!("A10BC", drop_unfinished_metrics_to_fit(csv, 5));
|
||||
|
||||
let csv = "A";
|
||||
assert_eq!("A", drop_unfinished_metrics_to_fit(csv, 5));
|
||||
|
||||
let csv = "A,B";
|
||||
assert_eq!("A,B", drop_unfinished_metrics_to_fit(csv, 5));
|
||||
}
|
||||
}
|
|
@ -529,17 +529,11 @@ mod test {
|
|||
|
||||
**New this release:**
|
||||
- :tada: (all, [smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446), [aws-sdk#123](https://github.com/aws/aws-sdk/issues/123), @external-contrib, @other-external-dev) I made a change to update the code generator
|
||||
- :tada: (all, [smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446), [smithy-rs#447](https://github.com/smithy-lang/smithy-rs/issues/447), @external-contrib, @other-external-dev) I made a change to update the code generator
|
||||
|
||||
**Update guide:**
|
||||
blah blah
|
||||
- (all, [smithy-rs#200](https://github.com/smithy-lang/smithy-rs/issues/200), @another-contrib) I made a minor change
|
||||
|
||||
**Contributors**
|
||||
Thank you for your contributions! ❤
|
||||
- @another-contrib ([smithy-rs#200](https://github.com/smithy-lang/smithy-rs/issues/200))
|
||||
- @external-contrib ([smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446), [smithy-rs#447](https://github.com/smithy-lang/smithy-rs/issues/447))
|
||||
- @other-external-dev ([smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446), [smithy-rs#447](https://github.com/smithy-lang/smithy-rs/issues/447))
|
||||
- @external-contrib ([smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446))
|
||||
- @other-external-dev ([smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446))
|
||||
|
||||
"#;
|
||||
|
||||
|
@ -586,16 +580,6 @@ new_feature: true
|
|||
bug_fix: false
|
||||
---
|
||||
I made a change to update the code generator
|
||||
"#;
|
||||
let smithy_rs_entry3 = r#"---
|
||||
applies_to: ["client", "server"]
|
||||
authors: ["another-contrib"]
|
||||
references: ["smithy-rs#200"]
|
||||
breaking: false
|
||||
new_feature: false
|
||||
bug_fix: false
|
||||
---
|
||||
I made a minor change
|
||||
"#;
|
||||
let aws_sdk_entry1 = r#"---
|
||||
applies_to: ["aws-sdk-rust"]
|
||||
|
@ -616,19 +600,6 @@ new_feature: true
|
|||
bug_fix: false
|
||||
---
|
||||
I made a change to update the code generator
|
||||
"#;
|
||||
let smithy_rs_entry4 = r#"---
|
||||
applies_to: ["client", "server"]
|
||||
authors: ["external-contrib", "other-external-dev"]
|
||||
references: ["smithy-rs#446", "smithy-rs#447"]
|
||||
breaking: false
|
||||
new_feature: true
|
||||
bug_fix: false
|
||||
---
|
||||
I made a change to update the code generator
|
||||
|
||||
**Update guide:**
|
||||
blah blah
|
||||
"#;
|
||||
|
||||
// We won't handwrite changelog entries for model updates, and they are still provided in
|
||||
|
@ -656,10 +627,8 @@ message = "Some API change"
|
|||
[
|
||||
smithy_rs_entry1,
|
||||
smithy_rs_entry2,
|
||||
smithy_rs_entry3,
|
||||
aws_sdk_entry1,
|
||||
aws_sdk_entry2,
|
||||
smithy_rs_entry4,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
|
Loading…
Reference in New Issue