From 2c993e53afe37d2c90b5a722a3d36ea565c00592 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Thu, 7 Dec 2023 09:19:14 -0800 Subject: [PATCH 1/5] Make delay between crate publishes configurable and reduce default (#3290) This change reduces the time delay between crate publishes from 5 seconds down to 1, and makes it configurable in case this leads to release issues. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --- tools/ci-build/publisher/src/subcommand/publish.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/ci-build/publisher/src/subcommand/publish.rs b/tools/ci-build/publisher/src/subcommand/publish.rs index dfa2c7af54..4a8090de02 100644 --- a/tools/ci-build/publisher/src/subcommand/publish.rs +++ b/tools/ci-build/publisher/src/subcommand/publish.rs @@ -23,6 +23,8 @@ use std::path::{Path, PathBuf}; use std::time::Duration; use tracing::info; +const DEFAULT_DELAY_MILLIS: usize = 1000; + #[derive(Parser, Debug)] pub struct PublishArgs { /// Path containing the crates to publish. Crates will be discovered recursively @@ -32,18 +34,24 @@ pub struct PublishArgs { /// Don't prompt for confirmation before publishing #[clap(short('y'))] skip_confirmation: bool, + + /// Time delay between crate publishes to avoid crates.io throttling errors. + #[clap(long)] + delay_millis: Option, } pub async fn subcommand_publish( PublishArgs { location, skip_confirmation, + delay_millis, }: &PublishArgs, ) -> Result<()> { // Make sure cargo exists cargo::confirm_installed_on_path()?; let location = resolve_publish_location(location); + let delay_millis = Duration::from_millis(delay_millis.unwrap_or(DEFAULT_DELAY_MILLIS) as _); info!("Discovering crates to publish..."); let (batches, stats) = discover_and_validate_package_batches(Fs::Real, &location).await?; @@ -60,7 +68,7 @@ pub async fn subcommand_publish( publish(&package.handle, &package.crate_path).await?; // Keep things slow to avoid getting throttled by crates.io - tokio::time::sleep(Duration::from_secs(5)).await; + tokio::time::sleep(delay_millis).await; // Sometimes it takes a little bit of time for the new package version // to become available after publish. If we proceed too quickly, then From bd9ad10ec2e747c75a477a18d6236e12c846930f Mon Sep 17 00:00:00 2001 From: ysaito1001 Date: Thu, 7 Dec 2023 11:50:35 -0600 Subject: [PATCH 2/5] Run `semver-checks` on PRs submitted by external contributors (#3291) ## Motivation and Context Enables `cargo semver-checks` in CI for PRs created by external contributors ## Description For instance, we skipped a run of `cargo semver-checks` in https://github.com/smithy-lang/smithy-rs/pull/3286 and failed to detect [a breaking change](https://github.com/smithy-lang/smithy-rs/pull/3286#discussion_r1416479632) programmatically. With this PR, the workflow will run a job `semver-checks` even if the preceding jobs `save-docker-login-token` or `acquire-base-image` are skipped. Those jobs are relevant when the PR made changes to build tools, which is less likely for PRs created by external contributors, so it's reasonable to skip them and still run the `semver-checks` job. Furthermore, this PR enables `semver-checks` to run against all crates in `tmp-codegen-diff/aws-sdk/sdk/`, not just those limited by `list(os.listdir())[:10]`. ## Testing Tested the change against [a dummy PR](https://github.com/smithy-lang/smithy-rs/pull/3288) I created from my fork of `smithy-rs`. Specifically, `semver-checks` [caught the aforementioned breaking change](https://github.com/smithy-lang/smithy-rs/actions/runs/7121830175/job/19391798131#step:4:681) in CI. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --- .github/workflows/ci-pr.yml | 6 ++++++ tools/ci-scripts/codegen-diff/semver-checks.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml index 6e7b00603f..2635554df2 100644 --- a/.github/workflows/ci-pr.yml +++ b/.github/workflows/ci-pr.yml @@ -114,6 +114,12 @@ jobs: needs: - save-docker-login-token - acquire-base-image + # We need `always` here otherwise this job won't run if the previous job has been skipped + # See https://samanpavel.medium.com/github-actions-conditional-job-execution-e6aa363d2867 + if: | + always() && + !contains(needs.*.result, 'failure') && + !contains(needs.*.result, 'cancelled') steps: - uses: actions/checkout@v3 with: diff --git a/tools/ci-scripts/codegen-diff/semver-checks.py b/tools/ci-scripts/codegen-diff/semver-checks.py index 1632242fc0..855cb4f2fa 100755 --- a/tools/ci-scripts/codegen-diff/semver-checks.py +++ b/tools/ci-scripts/codegen-diff/semver-checks.py @@ -37,7 +37,7 @@ def main(skip_generation=False): deny_list = [ # add crate names here to exclude them from the semver checks ] - for path in list(os.listdir())[:10]: + for path in os.listdir(): eprint(f'checking {path}...', end='') if path in deny_list: eprint(f"skipping {path} because it is in 'deny_list'") From bb2c129481f9b4e896999622df4afd947a6f3053 Mon Sep 17 00:00:00 2001 From: ysaito1001 Date: Thu, 7 Dec 2023 16:52:51 -0600 Subject: [PATCH 3/5] Upgrade jsoup to 1.16.2 (#3296) ## Motivation and Context Upgrades `jsoup` to 1.16.2, a version that we know is supported internally. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --- aws/sdk-codegen/build.gradle.kts | 2 +- codegen-core/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/sdk-codegen/build.gradle.kts b/aws/sdk-codegen/build.gradle.kts index f2eb5b4492..6b255bd5a3 100644 --- a/aws/sdk-codegen/build.gradle.kts +++ b/aws/sdk-codegen/build.gradle.kts @@ -23,7 +23,7 @@ val smithyVersion: String by project dependencies { implementation(project(":codegen-core")) implementation(project(":codegen-client")) - implementation("org.jsoup:jsoup:1.15.3") + implementation("org.jsoup:jsoup:1.16.2") implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion") implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion") implementation("software.amazon.smithy:smithy-rules-engine:$smithyVersion") diff --git a/codegen-core/build.gradle.kts b/codegen-core/build.gradle.kts index c4b3283289..e72667f898 100644 --- a/codegen-core/build.gradle.kts +++ b/codegen-core/build.gradle.kts @@ -23,7 +23,7 @@ val smithyVersion: String by project dependencies { implementation(kotlin("stdlib-jdk8")) - implementation("org.jsoup:jsoup:1.15.3") + implementation("org.jsoup:jsoup:1.16.2") api("software.amazon.smithy:smithy-codegen-core:$smithyVersion") api("com.moandjiezana.toml:toml4j:0.7.2") implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion") From b09b02f33241d9fbc6b6da4e96c0db4511a3d755 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 8 Dec 2023 10:19:29 -0500 Subject: [PATCH 4/5] Allow lossless conversions from float into integral types (#3294) ## Motivation and Context Some APIs return JSON values that are intended to be represented by integral types but are returned as floating values e.g `[1.0, -2.0, 25.0]`. This allows those values to be converted into Integral types. ## Description This uses a bidirectional conversion to check if a float can be losslessly converted into a integral type. This can have issues at the limits of i64::MAX but I think that's probably acceptable. These values would be represented imprecisely by floats already. ## Testing Added additional unit tests of the behavior. ## Checklist - [ ] I have updated `CHANGELOG.next.toml` if I made changes to the smithy-rs codegen or runtime crates - [ ] I have updated `CHANGELOG.next.toml` if I made changes to the AWS SDK, generated SDK code, or SDK runtime crates ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --- CHANGELOG.next.toml | 6 +++ rust-runtime/aws-smithy-types/src/number.rs | 53 ++++++++++++++++----- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 58811865e2..e170284918 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -79,3 +79,9 @@ message = "Expose local socket address from ConnectionMetadata." references = ["aws-sdk-rust#990"] meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } author = "declanvk" + +[[smithy-rs]] +message = "[`Number`](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/enum.Number.html) `TryInto` implementations now succesfully convert from `f64` to numeric types when no precision is lost. This fixes some deserialization issues where numbers like `25.0` were sent when `Byte` fields were expected." +references = ["smithy-rs#3294"] +meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "all" } +author = "rcoh" diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs index 85488b1299..4e546a9744 100644 --- a/rust-runtime/aws-smithy-types/src/number.rs +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -77,9 +77,7 @@ macro_rules! to_unsigned_integer_converter { Number::NegInt(v) => { Err(TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(v).into()) } - Number::Float(v) => { - Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) - } + Number::Float(v) => attempt_lossless!(v, $typ), } } } @@ -102,9 +100,7 @@ macro_rules! to_signed_integer_converter { match value { Number::PosInt(v) => Ok(Self::try_from(v)?), Number::NegInt(v) => Ok(Self::try_from(v)?), - Number::Float(v) => { - Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) - } + Number::Float(v) => attempt_lossless!(v, $typ), } } } @@ -115,6 +111,17 @@ macro_rules! to_signed_integer_converter { }; } +macro_rules! attempt_lossless { + ($value: expr, $typ: ty) => {{ + let converted = $value as $typ; + if (converted as f64 == $value) { + Ok(converted) + } else { + Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion($value).into()) + } + }}; +} + /// Converts to a `u64`. The conversion fails if it is lossy. impl TryFrom for u64 { type Error = TryFromNumberError; @@ -125,9 +132,7 @@ impl TryFrom for u64 { Number::NegInt(v) => { Err(TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(v).into()) } - Number::Float(v) => { - Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) - } + Number::Float(v) => attempt_lossless!(v, u64), } } } @@ -142,9 +147,7 @@ impl TryFrom for i64 { match value { Number::PosInt(v) => Ok(Self::try_from(v)?), Number::NegInt(v) => Ok(v), - Number::Float(v) => { - Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) - } + Number::Float(v) => attempt_lossless!(v, i64), } } } @@ -236,6 +239,7 @@ mod test { } )); } + assert_eq!($typ::try_from(Number::Float(25.0)).unwrap(), 25); }; } @@ -302,6 +306,13 @@ mod test { } )); } + + let range = || ($typ::MIN..=$typ::MAX); + + for val in range().take(1024).chain(range().rev().take(1024)) { + assert_eq!(val, $typ::try_from(Number::Float(val as f64)).unwrap()); + $typ::try_from(Number::Float((val as f64) + 0.1)).expect_err("not equivalent"); + } }; } @@ -318,6 +329,19 @@ mod test { } )); } + let range = || (i64::MIN..=i64::MAX); + + for val in range().take(1024).chain(range().rev().take(1024)) { + // if we can actually represent the value + if ((val as f64) as i64) == val { + assert_eq!(val, i64::try_from(Number::Float(val as f64)).unwrap()); + } + let fval = val as f64; + // at the limits of the range, we don't have this precision + if (fval + 0.1).fract() != 0.0 { + i64::try_from(Number::Float((val as f64) + 0.1)).expect_err("not equivalent"); + } + } } #[test] @@ -333,6 +357,11 @@ mod test { #[test] fn to_i8() { to_signed_converter_tests!(i8); + i8::try_from(Number::Float(-3200000.0)).expect_err("overflow"); + i8::try_from(Number::Float(32.1)).expect_err("imprecise"); + i8::try_from(Number::Float(i8::MAX as f64 + 0.1)).expect_err("imprecise"); + i8::try_from(Number::Float(f64::NAN)).expect_err("nan"); + i8::try_from(Number::Float(f64::INFINITY)).expect_err("nan"); } #[test] From 0bcc19362879b1c11ef858496dbcc7330d67bd40 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Mon, 27 Nov 2023 15:03:28 -0500 Subject: [PATCH 5/5] Add the `docsrs` autocfg attr to all crates This also adds it to generated crates, and adds an autofix+lint to manage these attributes. --- CHANGELOG.next.toml | 12 ++++ aws/rust-runtime/aws-config/src/lib.rs | 4 +- .../aws-credential-types/src/lib.rs | 3 + aws/rust-runtime/aws-endpoint/src/lib.rs | 3 + aws/rust-runtime/aws-http/src/lib.rs | 3 + aws/rust-runtime/aws-hyper/src/lib.rs | 3 + aws/rust-runtime/aws-inlineable/src/lib.rs | 3 + aws/rust-runtime/aws-runtime-api/src/lib.rs | 3 + aws/rust-runtime/aws-runtime/src/lib.rs | 3 + aws/rust-runtime/aws-sig-auth/src/lib.rs | 3 + aws/rust-runtime/aws-sigv4/src/lib.rs | 3 + aws/rust-runtime/aws-types/src/lib.rs | 3 + .../core/smithy/generators/LibRsGenerator.kt | 2 + rust-runtime/aws-smithy-async/src/lib.rs | 3 + rust-runtime/aws-smithy-checksums/src/lib.rs | 3 + rust-runtime/aws-smithy-client/src/lib.rs | 3 + .../aws-smithy-eventstream/src/lib.rs | 3 + rust-runtime/aws-smithy-http-auth/src/lib.rs | 3 + .../aws-smithy-http-server-python/src/lib.rs | 3 + .../src/lib.rs | 4 ++ .../aws-smithy-http-server/src/lib.rs | 3 + rust-runtime/aws-smithy-http-tower/src/lib.rs | 3 + rust-runtime/aws-smithy-http/src/lib.rs | 3 + rust-runtime/aws-smithy-json/src/lib.rs | 3 + .../aws-smithy-protocol-test/src/lib.rs | 3 + rust-runtime/aws-smithy-query/src/lib.rs | 3 + .../aws-smithy-runtime-api/src/lib.rs | 3 + rust-runtime/aws-smithy-runtime/src/lib.rs | 4 +- .../aws-smithy-types-convert/src/lib.rs | 3 + rust-runtime/aws-smithy-types/src/lib.rs | 5 +- rust-runtime/aws-smithy-xml/src/lib.rs | 3 + rust-runtime/inlineable/src/lib.rs | 3 + tools/ci-build/sdk-lints/src/anchor.rs | 24 +++++--- tools/ci-build/sdk-lints/src/lib_rs_attr.rs | 60 +++++++++++++++++++ .../ci-build/sdk-lints/src/lint_cargo_toml.rs | 1 + tools/ci-build/sdk-lints/src/main.rs | 4 ++ tools/ci-build/sdk-lints/src/readmes.rs | 8 ++- 37 files changed, 194 insertions(+), 12 deletions(-) create mode 100644 tools/ci-build/sdk-lints/src/lib_rs_attr.rs diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 58811865e2..472bf3870d 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -79,3 +79,15 @@ message = "Expose local socket address from ConnectionMetadata." references = ["aws-sdk-rust#990"] meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } author = "declanvk" + +[[smithy-rs]] +message = "All generated docs now include docsrs labels when features are required" +references = ["smithy-rs#3121", "smithy-rs#3295"] +meta = { "breaking" = false, "tada" = true, "bug" = false, "target" = "all" } +author = "rcoh" + +[[aws-sdk-rust]] +message = "All generated docs now include docsrs labels when features are required" +references = ["smithy-rs#3121", "smithy-rs#3295"] +meta = { "breaking" = false, "tada" = true, "bug" = false } +author = "rcoh" diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index 3feb455382..8b67d520cc 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![warn( missing_debug_implementations, @@ -11,7 +14,6 @@ rustdoc::missing_crate_level_docs, unreachable_pub )] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] //! `aws-config` provides implementations of region and credential resolution. //! diff --git a/aws/rust-runtime/aws-credential-types/src/lib.rs b/aws/rust-runtime/aws-credential-types/src/lib.rs index 58a3148eb8..e2bb7858ff 100644 --- a/aws/rust-runtime/aws-credential-types/src/lib.rs +++ b/aws/rust-runtime/aws-credential-types/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! `aws-credential-types` provides types concerned with AWS SDK credentials including: //! * Traits for credentials providers and for credentials caching //! * An opaque struct representing credentials diff --git a/aws/rust-runtime/aws-endpoint/src/lib.rs b/aws/rust-runtime/aws-endpoint/src/lib.rs index 2819d85118..7dcd32f85b 100644 --- a/aws/rust-runtime/aws-endpoint/src/lib.rs +++ b/aws/rust-runtime/aws-endpoint/src/lib.rs @@ -3,4 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! This crate is no longer used by the AWS SDK and is deprecated. diff --git a/aws/rust-runtime/aws-http/src/lib.rs b/aws/rust-runtime/aws-http/src/lib.rs index a5a670988c..091568b10a 100644 --- a/aws/rust-runtime/aws-http/src/lib.rs +++ b/aws/rust-runtime/aws-http/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! AWS-specific middleware implementations and HTTP-related features. #![allow(clippy::derive_partial_eq_without_eq)] diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 232f28ce9f..d6b444da30 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![deprecated( since = "0.3.0", note = "The functionality of this crate is included in individual AWS services." diff --git a/aws/rust-runtime/aws-inlineable/src/lib.rs b/aws/rust-runtime/aws-inlineable/src/lib.rs index 3ff04ff755..0ae9627703 100644 --- a/aws/rust-runtime/aws-inlineable/src/lib.rs +++ b/aws/rust-runtime/aws-inlineable/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! Collection of modules that get conditionally included directly into the code generated //! SDK service crates. For example, when generating S3, the `s3_errors` module will get copied //! into the generated S3 crate to support the code generator. diff --git a/aws/rust-runtime/aws-runtime-api/src/lib.rs b/aws/rust-runtime/aws-runtime-api/src/lib.rs index c66728daf4..899829fca1 100644 --- a/aws/rust-runtime/aws-runtime-api/src/lib.rs +++ b/aws/rust-runtime/aws-runtime-api/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! Runtime support code for the AWS SDK. This crate isn't intended to be used directly. #![warn( diff --git a/aws/rust-runtime/aws-runtime/src/lib.rs b/aws/rust-runtime/aws-runtime/src/lib.rs index 085ec4fc97..df8415f20e 100644 --- a/aws/rust-runtime/aws-runtime/src/lib.rs +++ b/aws/rust-runtime/aws-runtime/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! Runtime support code for the AWS SDK. This crate isn't intended to be used directly. #![warn( diff --git a/aws/rust-runtime/aws-sig-auth/src/lib.rs b/aws/rust-runtime/aws-sig-auth/src/lib.rs index 2819d85118..7dcd32f85b 100644 --- a/aws/rust-runtime/aws-sig-auth/src/lib.rs +++ b/aws/rust-runtime/aws-sig-auth/src/lib.rs @@ -3,4 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! This crate is no longer used by the AWS SDK and is deprecated. diff --git a/aws/rust-runtime/aws-sigv4/src/lib.rs b/aws/rust-runtime/aws-sigv4/src/lib.rs index 5fe83a0bf5..a9f60afba8 100644 --- a/aws/rust-runtime/aws-sigv4/src/lib.rs +++ b/aws/rust-runtime/aws-sigv4/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! Provides functions for calculating Sigv4 signing keys, signatures, and //! optional utilities for signing HTTP requests and Event Stream messages. diff --git a/aws/rust-runtime/aws-types/src/lib.rs b/aws/rust-runtime/aws-types/src/lib.rs index d9f76ecd7c..83b55b8654 100644 --- a/aws/rust-runtime/aws-types/src/lib.rs +++ b/aws/rust-runtime/aws-types/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! Cross-service types for the AWS SDK. #![allow(clippy::derive_partial_eq_without_eq)] diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index ed05e0c1f0..ab87afa1b8 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -12,6 +12,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.containerDocs import software.amazon.smithy.rust.codegen.core.rustlang.escape import software.amazon.smithy.rust.codegen.core.rustlang.isNotEmpty +import software.amazon.smithy.rust.codegen.core.rustlang.rawRust import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.smithy.CoreRustSettings import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomization @@ -50,6 +51,7 @@ class LibRsGenerator( if (requireDocs) { rust("##![warn(missing_docs)]") } + rawRust("#![cfg_attr(docsrs, feature(doc_auto_cfg))]") // Allow for overriding the default service docs via customization val defaultServiceDocs = settings.getService(model).getTrait()?.value diff --git a/rust-runtime/aws-smithy-async/src/lib.rs b/rust-runtime/aws-smithy-async/src/lib.rs index 59fdc54e0f..e32464eb7c 100644 --- a/rust-runtime/aws-smithy-async/src/lib.rs +++ b/rust-runtime/aws-smithy-async/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![warn( missing_docs, diff --git a/rust-runtime/aws-smithy-checksums/src/lib.rs b/rust-runtime/aws-smithy-checksums/src/lib.rs index 372bc467e4..1bc7b2fda3 100644 --- a/rust-runtime/aws-smithy-checksums/src/lib.rs +++ b/rust-runtime/aws-smithy-checksums/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![warn( // missing_docs, diff --git a/rust-runtime/aws-smithy-client/src/lib.rs b/rust-runtime/aws-smithy-client/src/lib.rs index 32e46abdb4..8bbf760e23 100644 --- a/rust-runtime/aws-smithy-client/src/lib.rs +++ b/rust-runtime/aws-smithy-client/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! This crate is no longer used by smithy-rs and is deprecated. #![warn( diff --git a/rust-runtime/aws-smithy-eventstream/src/lib.rs b/rust-runtime/aws-smithy-eventstream/src/lib.rs index 5171471d2f..36f99e9a8e 100644 --- a/rust-runtime/aws-smithy-eventstream/src/lib.rs +++ b/rust-runtime/aws-smithy-eventstream/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![warn( // missing_docs, diff --git a/rust-runtime/aws-smithy-http-auth/src/lib.rs b/rust-runtime/aws-smithy-http-auth/src/lib.rs index f54985f0c9..91990c7344 100644 --- a/rust-runtime/aws-smithy-http-auth/src/lib.rs +++ b/rust-runtime/aws-smithy-http-auth/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![warn( missing_docs, rustdoc::missing_crate_level_docs, diff --git a/rust-runtime/aws-smithy-http-server-python/src/lib.rs b/rust-runtime/aws-smithy-http-server-python/src/lib.rs index 17b7a96a03..d11b5a9622 100644 --- a/rust-runtime/aws-smithy-http-server-python/src/lib.rs +++ b/rust-runtime/aws-smithy-http-server-python/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![cfg_attr(docsrs, feature(doc_cfg))] diff --git a/rust-runtime/aws-smithy-http-server-typescript/src/lib.rs b/rust-runtime/aws-smithy-http-server-typescript/src/lib.rs index 35d0f3613a..6a0366b762 100644 --- a/rust-runtime/aws-smithy-http-server-typescript/src/lib.rs +++ b/rust-runtime/aws-smithy-http-server-typescript/src/lib.rs @@ -2,3 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ + +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ diff --git a/rust-runtime/aws-smithy-http-server/src/lib.rs b/rust-runtime/aws-smithy-http-server/src/lib.rs index a7a78733b2..4ad140f2ed 100644 --- a/rust-runtime/aws-smithy-http-server/src/lib.rs +++ b/rust-runtime/aws-smithy-http-server/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![cfg_attr(docsrs, feature(doc_cfg))] diff --git a/rust-runtime/aws-smithy-http-tower/src/lib.rs b/rust-runtime/aws-smithy-http-tower/src/lib.rs index 32e46abdb4..8bbf760e23 100644 --- a/rust-runtime/aws-smithy-http-tower/src/lib.rs +++ b/rust-runtime/aws-smithy-http-tower/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! This crate is no longer used by smithy-rs and is deprecated. #![warn( diff --git a/rust-runtime/aws-smithy-http/src/lib.rs b/rust-runtime/aws-smithy-http/src/lib.rs index 618f51ed31..189626205f 100644 --- a/rust-runtime/aws-smithy-http/src/lib.rs +++ b/rust-runtime/aws-smithy-http/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![warn( missing_docs, rustdoc::missing_crate_level_docs, diff --git a/rust-runtime/aws-smithy-json/src/lib.rs b/rust-runtime/aws-smithy-json/src/lib.rs index 08c324772e..7fc5276042 100644 --- a/rust-runtime/aws-smithy-json/src/lib.rs +++ b/rust-runtime/aws-smithy-json/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![warn( // missing_docs, diff --git a/rust-runtime/aws-smithy-protocol-test/src/lib.rs b/rust-runtime/aws-smithy-protocol-test/src/lib.rs index 92d9f5c4f3..07839e2a38 100644 --- a/rust-runtime/aws-smithy-protocol-test/src/lib.rs +++ b/rust-runtime/aws-smithy-protocol-test/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![warn( // missing_docs, // rustdoc::missing_crate_level_docs, diff --git a/rust-runtime/aws-smithy-query/src/lib.rs b/rust-runtime/aws-smithy-query/src/lib.rs index 9ce7799718..84f4d37620 100644 --- a/rust-runtime/aws-smithy-query/src/lib.rs +++ b/rust-runtime/aws-smithy-query/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![warn( // missing_docs, diff --git a/rust-runtime/aws-smithy-runtime-api/src/lib.rs b/rust-runtime/aws-smithy-runtime-api/src/lib.rs index be0ca84d61..92ddf65464 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/lib.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![warn( missing_docs, rustdoc::missing_crate_level_docs, diff --git a/rust-runtime/aws-smithy-runtime/src/lib.rs b/rust-runtime/aws-smithy-runtime/src/lib.rs index 3a7974e9b5..36dcd854ec 100644 --- a/rust-runtime/aws-smithy-runtime/src/lib.rs +++ b/rust-runtime/aws-smithy-runtime/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! Runtime support logic and types for smithy-rs generated code. //! //! # Crate Features @@ -17,7 +20,6 @@ unreachable_pub, rust_2018_idioms )] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] /// Runtime support logic for generated clients. #[cfg(feature = "client")] diff --git a/rust-runtime/aws-smithy-types-convert/src/lib.rs b/rust-runtime/aws-smithy-types-convert/src/lib.rs index e44f5c1c53..bd7ae8a784 100644 --- a/rust-runtime/aws-smithy-types-convert/src/lib.rs +++ b/rust-runtime/aws-smithy-types-convert/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! Conversions between `aws-smithy-types` and the types of frequently used Rust libraries. #![allow(clippy::derive_partial_eq_without_eq)] diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index 79c0a13f5b..ed53de191b 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ //! Protocol-agnostic types for smithy-rs. #![allow(clippy::derive_partial_eq_without_eq)] @@ -13,7 +16,7 @@ rust_2018_idioms, unreachable_pub )] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] + pub mod base64; pub mod body; pub mod byte_stream; diff --git a/rust-runtime/aws-smithy-xml/src/lib.rs b/rust-runtime/aws-smithy-xml/src/lib.rs index a179c0993c..48952cfced 100644 --- a/rust-runtime/aws-smithy-xml/src/lib.rs +++ b/rust-runtime/aws-smithy-xml/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #![allow(clippy::derive_partial_eq_without_eq)] #![warn( // missing_docs, diff --git a/rust-runtime/inlineable/src/lib.rs b/rust-runtime/inlineable/src/lib.rs index ab322f36ab..bcb9a1e7fe 100644 --- a/rust-runtime/inlineable/src/lib.rs +++ b/rust-runtime/inlineable/src/lib.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ #[allow(dead_code)] mod aws_query_compatible_errors; #[allow(unused)] diff --git a/tools/ci-build/sdk-lints/src/anchor.rs b/tools/ci-build/sdk-lints/src/anchor.rs index 34ebe53e3c..d542fc2986 100644 --- a/tools/ci-build/sdk-lints/src/anchor.rs +++ b/tools/ci-build/sdk-lints/src/anchor.rs @@ -19,6 +19,7 @@ pub fn replace_anchor( haystack: &mut String, anchors: &(impl AsRef, impl AsRef), new_content: &str, + default_insertion_position: Option, ) -> anyhow::Result { let anchor_start = anchors.0.as_ref(); let anchor_end = anchors.1.as_ref(); @@ -27,10 +28,19 @@ pub fn replace_anchor( if haystack.contains(anchor_end) { bail!("found end anchor but no start anchor"); } - haystack.push('\n'); - haystack.push_str(anchor_start); - haystack.push_str(new_content); - haystack.push_str(anchor_end); + + let (prefix, suffix) = match default_insertion_position { + Some(position) => haystack.split_at(position), + None => (haystack.as_ref(), ""), + }; + let mut out = String::new(); + out.push_str(prefix); + out.push('\n'); + out.push_str(anchor_start); + out.push_str(new_content); + out.push_str(anchor_end); + out.push_str(suffix); + *haystack = out; return Ok(true); } let start = start.unwrap_or_else(|| haystack.find(anchor_start).expect("must be present")); @@ -59,7 +69,7 @@ mod test { #[test] fn updates_empty() { let mut text = "this is the start".to_string(); - assert!(replace_anchor(&mut text, &anchors("foo"), "hello!").unwrap()); + assert!(replace_anchor(&mut text, &anchors("foo"), "hello!", None).unwrap()); assert_eq!( text, "this is the start\nhello!" @@ -70,13 +80,13 @@ mod test { fn updates_existing() { let mut text = "this is the start\nhello!".to_string(); - assert!(replace_anchor(&mut text, &anchors("foo"), "goodbye!").unwrap()); + assert!(replace_anchor(&mut text, &anchors("foo"), "goodbye!", None).unwrap()); assert_eq!( text, "this is the start\ngoodbye!" ); // no replacement should return false - assert!(!replace_anchor(&mut text, &anchors("foo"), "goodbye!").unwrap(),) + assert!(!replace_anchor(&mut text, &anchors("foo"), "goodbye!", None).unwrap(),) } } diff --git a/tools/ci-build/sdk-lints/src/lib_rs_attr.rs b/tools/ci-build/sdk-lints/src/lib_rs_attr.rs new file mode 100644 index 0000000000..4a226dc9d9 --- /dev/null +++ b/tools/ci-build/sdk-lints/src/lib_rs_attr.rs @@ -0,0 +1,60 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use std::path::{Path, PathBuf}; + +use crate::all_runtime_crates; +use crate::anchor::replace_anchor; +use crate::lint::{Fix, Lint, LintError}; + +/// Manages a standard set of `#![crate_level]` attributes +pub(super) struct StandardizedRuntimeCrateLibRsAttributes; + +impl Lint for StandardizedRuntimeCrateLibRsAttributes { + fn name(&self) -> &str { + "Checking for the correct docs.rs attributes" + } + + fn files_to_check(&self) -> anyhow::Result> { + Ok(all_runtime_crates()? + .map(|crte| crte.join("src/lib.rs")) + .collect()) + } +} + +const DOCS_AUTO_CFG: &str = "#![cfg_attr(docsrs, feature(doc_auto_cfg))]"; + +fn check_for_auto_cfg(path: impl AsRef) -> anyhow::Result> { + let contents = std::fs::read_to_string(path)?; + if !contents.contains(DOCS_AUTO_CFG) { + return Ok(vec![LintError::new("missing docsrs header")]); + } + Ok(vec![]) +} + +impl Fix for StandardizedRuntimeCrateLibRsAttributes { + fn fix(&self, path: impl AsRef) -> anyhow::Result<(Vec, String)> { + let contents = std::fs::read_to_string(&path)?; + // ensure there is only one in the crate + let mut contents = contents.replace(DOCS_AUTO_CFG, ""); + let anchor_start = "/* Automatically managed default lints */\n"; + let anchor_end = "\n/* End of automatically managed default lints */"; + // Find the end of the license header + if let Some(pos) = contents.find("*/") { + let newline = contents[pos..] + .find('\n') + .ok_or(anyhow::Error::msg("couldn't find a newline"))? + + 1 + + pos; + replace_anchor( + &mut contents, + &(anchor_start, anchor_end), + DOCS_AUTO_CFG, + Some(newline), + )?; + }; + check_for_auto_cfg(path).map(|errs| (errs, contents)) + } +} diff --git a/tools/ci-build/sdk-lints/src/lint_cargo_toml.rs b/tools/ci-build/sdk-lints/src/lint_cargo_toml.rs index c7dee81ed2..5b253e42d6 100644 --- a/tools/ci-build/sdk-lints/src/lint_cargo_toml.rs +++ b/tools/ci-build/sdk-lints/src/lint_cargo_toml.rs @@ -224,6 +224,7 @@ fn fix_docs_rs(contents: &str) -> Result { &mut new, &("[package.metadata.docs.rs]", "# End of docs.rs metadata"), DEFAULT_DOCS_RS_SECTION, + None, )?; Ok(new) } diff --git a/tools/ci-build/sdk-lints/src/main.rs b/tools/ci-build/sdk-lints/src/main.rs index d05788387f..07af20e0d8 100644 --- a/tools/ci-build/sdk-lints/src/main.rs +++ b/tools/ci-build/sdk-lints/src/main.rs @@ -5,6 +5,7 @@ use crate::changelog::ChangelogNext; use crate::copyright::CopyrightHeader; +use crate::lib_rs_attr::StandardizedRuntimeCrateLibRsAttributes; use crate::lint::{Check, Fix, Lint, LintError, Mode}; use crate::lint_cargo_toml::{ CrateAuthor, CrateLicense, DocsRs, SdkExternalLintsExposesStableCrates, @@ -23,6 +24,7 @@ use std::{fs, io}; mod anchor; mod changelog; mod copyright; +mod lib_rs_attr; mod lint; mod lint_cargo_toml; mod readmes; @@ -140,6 +142,7 @@ fn main() -> Result<()> { } errs.extend(StableCratesExposeStableCrates::new()?.check_all()?); errs.extend(SdkExternalLintsExposesStableCrates::new()?.check_all()?); + errs.extend(StandardizedRuntimeCrateLibRsAttributes.check_all()?); ok(errs)? } Args::Fix { @@ -158,6 +161,7 @@ fn main() -> Result<()> { if docsrs_metadata || all { ok(DocsRs.fix_all(dry_run)?)?; } + ok(StandardizedRuntimeCrateLibRsAttributes.fix_all(dry_run)?)?; } } Ok(()) diff --git a/tools/ci-build/sdk-lints/src/readmes.rs b/tools/ci-build/sdk-lints/src/readmes.rs index 9259197cc1..2d5073a715 100644 --- a/tools/ci-build/sdk-lints/src/readmes.rs +++ b/tools/ci-build/sdk-lints/src/readmes.rs @@ -78,7 +78,11 @@ fn fix_readme(path: impl AsRef, to_be_used_directly: bool) -> Result<(bool let mut contents = fs::read_to_string(path.as_ref()) .with_context(|| format!("failure to read readme: {:?}", path.as_ref()))?; - let updated = - anchor::replace_anchor(&mut contents, &anchor::anchors("footer"), &footer_contents)?; + let updated = anchor::replace_anchor( + &mut contents, + &anchor::anchors("footer"), + &footer_contents, + None, + )?; Ok((updated, contents)) }