From 6ffd99000b0f79f6fef84ad807a097cd1eb52a02 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Thu, 11 Jan 2024 15:20:36 -0800 Subject: [PATCH] Implement runtime-versioner audit tool (#3332) This PR implements a build tool to audit runtime crate versions as part of CI and release. If a runtime crate doesn't have the special `0.0.0-smithy-rs-head` version number, then it is assumed to be independently versioned, and the audit tool will verify it is version bumped when any changes are made to it. Given that there isn't a complete/reliable semver checking tool for Rust yet, this tool isn't smart. It will rely on devs to correctly bump the version number when that is done. ---- _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.yml | 3 + aws/sdk/build.gradle.kts | 6 +- .../src/main/kotlin/aws/sdk/CrateVersioner.kt | 6 - tools/ci-build/Dockerfile | 6 +- tools/ci-build/changelogger/Cargo.lock | 45 +- tools/ci-build/publisher/Cargo.lock | 41 +- tools/ci-build/publisher/Cargo.toml | 2 +- tools/ci-build/publisher/src/lib.rs | 1 - tools/ci-build/publisher/src/publish.rs | 2 +- .../publisher/src/subcommand/fix_manifests.rs | 149 +- .../src/subcommand/fix_manifests/validate.rs | 146 +- .../publisher/src/subcommand/publish.rs | 2 +- tools/ci-build/publisher/src/yank.rs | 2 +- tools/ci-build/runtime-versioner/Cargo.lock | 1635 +++++++++++++++++ tools/ci-build/runtime-versioner/Cargo.toml | 29 + tools/ci-build/runtime-versioner/src/audit.rs | 259 +++ tools/ci-build/runtime-versioner/src/index.rs | 109 ++ tools/ci-build/runtime-versioner/src/main.rs | 82 + tools/ci-build/runtime-versioner/src/repo.rs | 43 + tools/ci-build/runtime-versioner/src/tag.rs | 120 ++ tools/ci-build/runtime-versioner/src/util.rs | 16 + .../runtime-versioner/test-common/Cargo.toml | 10 + .../runtime-versioner/test-common/src/lib.rs | 100 + .../runtime-versioner/test_data/.gitignore | 2 + .../runtime-versioner/test_data/Makefile | 22 + .../runtime-versioner/test_data/README.md | 14 + .../test_data/already_published_version.toml | 28 + .../test_data/base_crates_io_index.toml | 28 + .../test_data/test_base.git.tar.gz | Bin 0 -> 49188 bytes .../runtime-versioner/tests/test_audit.rs | 80 + .../tests/test_previous_release_tag.rs | 25 + tools/ci-build/sdk-lints/Cargo.lock | 534 +++--- tools/ci-build/sdk-versioner/Cargo.lock | 45 +- .../ci-build/smithy-rs-tool-common/Cargo.toml | 3 +- .../smithy-rs-tool-common/src/command.rs | 75 + .../src/git/get_current_tag.rs | 2 +- .../ci-build/smithy-rs-tool-common/src/lib.rs | 2 + .../src/retry.rs | 138 +- .../smithy-rs-tool-common/src/shell.rs | 10 +- tools/ci-cdk/canary-runner/Cargo.lock | 41 +- tools/ci-cdk/canary-runner/Cargo.toml | 2 +- tools/ci-scripts/check-rust-runtimes | 3 + tools/ci-scripts/check-tools | 1 + 43 files changed, 3282 insertions(+), 587 deletions(-) create mode 100644 tools/ci-build/runtime-versioner/Cargo.lock create mode 100644 tools/ci-build/runtime-versioner/Cargo.toml create mode 100644 tools/ci-build/runtime-versioner/src/audit.rs create mode 100644 tools/ci-build/runtime-versioner/src/index.rs create mode 100644 tools/ci-build/runtime-versioner/src/main.rs create mode 100644 tools/ci-build/runtime-versioner/src/repo.rs create mode 100644 tools/ci-build/runtime-versioner/src/tag.rs create mode 100644 tools/ci-build/runtime-versioner/src/util.rs create mode 100644 tools/ci-build/runtime-versioner/test-common/Cargo.toml create mode 100644 tools/ci-build/runtime-versioner/test-common/src/lib.rs create mode 100644 tools/ci-build/runtime-versioner/test_data/.gitignore create mode 100644 tools/ci-build/runtime-versioner/test_data/Makefile create mode 100644 tools/ci-build/runtime-versioner/test_data/README.md create mode 100644 tools/ci-build/runtime-versioner/test_data/already_published_version.toml create mode 100644 tools/ci-build/runtime-versioner/test_data/base_crates_io_index.toml create mode 100644 tools/ci-build/runtime-versioner/test_data/test_base.git.tar.gz create mode 100644 tools/ci-build/runtime-versioner/tests/test_audit.rs create mode 100644 tools/ci-build/runtime-versioner/tests/test_previous_release_tag.rs create mode 100644 tools/ci-build/smithy-rs-tool-common/src/command.rs rename tools/ci-build/{publisher => smithy-rs-tool-common}/src/retry.rs (55%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c3c6c4fe..ac4c84246 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,6 +92,7 @@ jobs: runner: smithy_ubuntu-latest_8-core - action: check-rust-runtimes runner: smithy_ubuntu-latest_8-core + fetch-depth: 0 - action: check-sdk-codegen-unit-tests runner: ubuntu-latest - action: check-server-codegen-integration-tests @@ -119,6 +120,8 @@ jobs: with: path: smithy-rs ref: ${{ inputs.git_ref }} + # Defaults to 1 if not set + fetch-depth: ${{ matrix.test.fetch-depth }} - name: Run ${{ matrix.test.action }} uses: ./smithy-rs/.github/actions/docker-build with: diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index 471fcff3c..7b263e0b5 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -358,11 +358,7 @@ tasks.register("fixManifests") { toolPath = publisherToolPath binaryName = "publisher" - arguments = mutableListOf("fix-manifests", "--location", outputDir.asFile.absolutePath).apply { - if (crateVersioner.independentVersioningEnabled()) { - add("--disable-version-number-validation") - } - } + arguments = mutableListOf("fix-manifests", "--location", outputDir.asFile.absolutePath) } tasks.register("hydrateReadme") { diff --git a/buildSrc/src/main/kotlin/aws/sdk/CrateVersioner.kt b/buildSrc/src/main/kotlin/aws/sdk/CrateVersioner.kt index e26f66a64..fbd768a2f 100644 --- a/buildSrc/src/main/kotlin/aws/sdk/CrateVersioner.kt +++ b/buildSrc/src/main/kotlin/aws/sdk/CrateVersioner.kt @@ -40,8 +40,6 @@ interface VersionCrate { moduleName: String, service: AwsService, ): String - - fun independentVersioningEnabled(): Boolean } class SynchronizedCrateVersioner( @@ -58,8 +56,6 @@ class SynchronizedCrateVersioner( moduleName: String, service: AwsService, ): String = sdkVersion - - override fun independentVersioningEnabled(): Boolean = sdkVersion == LOCAL_DEV_VERSION } private data class SemVer( @@ -130,8 +126,6 @@ class IndependentCrateVersioner( ) } - override fun independentVersioningEnabled(): Boolean = true - override fun decideCrateVersion( moduleName: String, service: AwsService, diff --git a/tools/ci-build/Dockerfile b/tools/ci-build/Dockerfile index 3017f05de..f6ce29bf0 100644 --- a/tools/ci-build/Dockerfile +++ b/tools/ci-build/Dockerfile @@ -82,10 +82,11 @@ RUN set -eux; \ cd smithy-rs; \ git checkout ${smithy_rs_commit_hash}; \ fi; \ - cargo install --locked --path tools/ci-build/publisher; \ cargo install --locked --path tools/ci-build/changelogger; \ cargo install --locked --path tools/ci-build/crate-hasher; \ cargo install --locked --path tools/ci-build/difftags; \ + cargo install --locked --path tools/ci-build/publisher; \ + cargo install --locked --path tools/ci-build/runtime-versioner; \ cargo install --locked --path tools/ci-build/sdk-lints; \ cargo install --locked --path tools/ci-build/sdk-versioner; \ chmod g+rw -R /opt/cargo/registry @@ -166,7 +167,8 @@ RUN set -eux; \ python3 \ python3-devel \ python3-pip \ - shadow-utils; \ + shadow-utils \ + tar; \ yum clean all; \ rm -rf /var/cache/yum; \ groupadd build; \ diff --git a/tools/ci-build/changelogger/Cargo.lock b/tools/ci-build/changelogger/Cargo.lock index d805f336a..c7de5cafa 100644 --- a/tools/ci-build/changelogger/Cargo.lock +++ b/tools/ci-build/changelogger/Cargo.lock @@ -40,7 +40,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -621,7 +621,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -723,18 +723,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -895,7 +895,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -942,6 +942,7 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "toml", "tracing", ] @@ -985,9 +986,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -1043,6 +1044,26 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "time" version = "0.3.30" @@ -1152,7 +1173,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1250,7 +1271,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -1284,7 +1305,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/tools/ci-build/publisher/Cargo.lock b/tools/ci-build/publisher/Cargo.lock index 96bf61925..8c4ffda50 100644 --- a/tools/ci-build/publisher/Cargo.lock +++ b/tools/ci-build/publisher/Cargo.lock @@ -51,7 +51,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -426,7 +426,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -829,7 +829,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -922,7 +922,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -990,9 +990,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -1028,9 +1028,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1212,7 +1212,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1316,6 +1316,7 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "tokio", "toml 0.5.11", "tracing", @@ -1360,9 +1361,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -1430,22 +1431,22 @@ checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1500,7 +1501,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1596,7 +1597,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1748,7 +1749,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -1782,7 +1783,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/tools/ci-build/publisher/Cargo.toml b/tools/ci-build/publisher/Cargo.toml index 8218e914e..ce6b7ba49 100644 --- a/tools/ci-build/publisher/Cargo.toml +++ b/tools/ci-build/publisher/Cargo.toml @@ -29,7 +29,7 @@ semver = "1.0" serde = { version = "1", features = ["derive"] } serde_json = "1" sha256 = "1" -smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common", features = ["async-shell"] } +smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common", features = ["async"] } tempfile = "3.3.0" thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } diff --git a/tools/ci-build/publisher/src/lib.rs b/tools/ci-build/publisher/src/lib.rs index 562880c5d..632e7b5b0 100644 --- a/tools/ci-build/publisher/src/lib.rs +++ b/tools/ci-build/publisher/src/lib.rs @@ -14,7 +14,6 @@ pub mod cargo; pub mod fs; pub mod package; pub mod publish; -pub mod retry; pub mod sort; pub mod subcommand; pub mod yank; diff --git a/tools/ci-build/publisher/src/publish.rs b/tools/ci-build/publisher/src/publish.rs index 59d4d48b5..151f00ac5 100644 --- a/tools/ci-build/publisher/src/publish.rs +++ b/tools/ci-build/publisher/src/publish.rs @@ -5,9 +5,9 @@ use crate::cargo; use crate::package::PackageHandle; -use crate::retry::{run_with_retry, BoxError, ErrorClass}; use crates_io_api::{AsyncClient, Error}; use once_cell::sync::Lazy; +use smithy_rs_tool_common::retry::{run_with_retry, BoxError, ErrorClass}; use smithy_rs_tool_common::shell::ShellOperation; use std::path::Path; use std::time::Duration; diff --git a/tools/ci-build/publisher/src/subcommand/fix_manifests.rs b/tools/ci-build/publisher/src/subcommand/fix_manifests.rs index ce0362878..78814cdad 100644 --- a/tools/ci-build/publisher/src/subcommand/fix_manifests.rs +++ b/tools/ci-build/publisher/src/subcommand/fix_manifests.rs @@ -16,7 +16,6 @@ use anyhow::{bail, Context, Result}; use clap::Parser; use semver::Version; use smithy_rs_tool_common::ci::running_in_ci; -use smithy_rs_tool_common::package::PackageStability; use std::collections::BTreeMap; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -40,17 +39,15 @@ pub struct FixManifestsArgs { /// Checks manifests rather than fixing them #[clap(long)] check: bool, - /// Disable expected version number validation. This should only be used - /// when SDK crates are being generated with independent version numbers. + /// UNUSED. Kept for backwards compatibility. Can be removed in the future when + /// the older commits that rely on it have been synced over in a SDK release. #[clap(long)] disable_version_number_validation: bool, } pub async fn subcommand_fix_manifests( FixManifestsArgs { - location, - check, - disable_version_number_validation, + location, check, .. }: &FixManifestsArgs, ) -> Result<()> { let mode = match check { @@ -61,7 +58,6 @@ pub async fn subcommand_fix_manifests( let mut manifests = read_manifests(Fs::Real, manifest_paths).await?; let versions = package_versions(&manifests)?; - validate::validate_before_fixes(&versions, *disable_version_number_validation)?; fix_manifests(Fs::Real, &versions, &mut manifests, mode).await?; validate::validate_after_fixes(location).await?; info!("Successfully fixed manifests!"); @@ -84,27 +80,6 @@ impl Manifest { ))), } } - - fn stability(&self) -> Result { - let value = self - .metadata - .get("package") - .and_then(|v| v.get("metadata")) - .and_then(|v| v.get("smithy-rs-release-tooling")) - .and_then(|v| v.get("stable")); - match value { - None => Ok(PackageStability::Unstable), - Some(value) => { - if value.as_bool().ok_or(anyhow::Error::msg(format!( - "unexpected stable setting: {value}" - )))? { - Ok(PackageStability::Stable) - } else { - Ok(PackageStability::Unstable) - } - } - } - } } struct Versions(BTreeMap); @@ -133,32 +108,11 @@ impl Versions { fn published(&self) -> VersionView { VersionView(self, FilterType::PublishedOnly) } - - fn published_crates(&self) -> impl Iterator + '_ { - self.0 - .iter() - .filter(|(_, v)| v.publish) - .map(|(k, v)| (k.as_str(), &v.version)) - } - - fn get(&self, crate_name: &str) -> Option<&Version> { - self.0.get(crate_name).map(|v| &v.version) - } - - fn stable(&self, crate_name: &str) -> Option { - match self.0.get(crate_name) { - Some(VersionWithMetadata { stability, .. }) => { - Some(*stability == PackageStability::Stable) - } - _ => None, - } - } } struct VersionWithMetadata { version: Version, publish: bool, - stability: PackageStability, } async fn read_manifests(fs: Fs, manifest_paths: Vec) -> Result> { @@ -182,7 +136,6 @@ fn package_versions(manifests: &[Manifest]) -> Result { None => continue, }; let publish = manifest.publish()?; - let stability = manifest.stability()?; let name = package .get("name") .and_then(|name| name.as_str()) @@ -196,14 +149,7 @@ fn package_versions(manifests: &[Manifest]) -> Result { anyhow::Error::msg(format!("{:?} is missing a package version", manifest.path)) })?; let version = parse_version(&manifest.path, version)?; - versions.insert( - name.into(), - VersionWithMetadata { - version, - publish, - stability, - }, - ); + versions.insert(name.into(), VersionWithMetadata { version, publish }); } Ok(Versions(versions)) } @@ -359,19 +305,16 @@ fn fix_manifest(versions: &Versions, manifest: &mut Manifest) -> Result { mod tests { use super::*; - fn make_versions<'a>( - versions: impl Iterator, - ) -> Versions { + fn make_versions<'a>(versions: impl Iterator) -> Versions { let map = versions .into_iter() - .map(|(name, version, publish, stability)| { + .map(|(name, version, publish)| { let publish = *publish; ( name.to_string(), VersionWithMetadata { version: Version::parse(version).unwrap(), publish, - stability: *stability, }, ) }) @@ -405,19 +348,9 @@ mod tests { metadata, }; let versions = &[ - ( - "local_build_something", - "0.2.0", - true, - PackageStability::Unstable, - ), - ( - "local_dev_something", - "0.1.0", - false, - PackageStability::Unstable, - ), - ("local_something", "1.1.3", false, PackageStability::Stable), + ("local_build_something", "0.2.0", true), + ("local_dev_something", "0.1.0", false), + ("local_something", "1.1.3", false), ]; let versions = make_versions(versions.iter()); fix_manifest(&versions, &mut manifest).expect_err("depends on unpublished local something"); @@ -451,19 +384,9 @@ mod tests { metadata, }; let versions = &[ - ( - "local_build_something", - "0.2.0", - true, - PackageStability::Unstable, - ), - ( - "local_dev_something", - "0.1.0", - false, - PackageStability::Unstable, - ), - ("local_something", "1.1.3", true, PackageStability::Stable), + ("local_build_something", "0.2.0", true), + ("local_dev_something", "0.1.0", false), + ("local_something", "1.1.3", true), ]; let versions = make_versions(versions.iter()); @@ -522,52 +445,4 @@ mod tests { "aws-sdk-rust/examples/foo/bar/Cargo.toml" )); } - - #[test] - fn test_package_stability_from_manifest() { - fn verify_package_stability_for_manifest( - manifest: &[u8], - expected_stability: PackageStability, - ) { - let metadata = toml::from_slice(manifest).unwrap(); - let manifest = Manifest { - path: "test".into(), - metadata, - }; - assert_eq!(expected_stability, manifest.stability().unwrap()); - } - - let stable_manifest = br#" - [package] - name = "test" - version = "1.0.0" - - [package.metadata.smithy-rs-release-tooling] - stable = true - "#; - verify_package_stability_for_manifest(stable_manifest, PackageStability::Stable); - - let explicitly_unstable_manifest = br#" - [package] - name = "test" - version = "0.1.0" - - [package.metadata.smithy-rs-release-tooling] - stable = false - "#; - verify_package_stability_for_manifest( - explicitly_unstable_manifest, - PackageStability::Unstable, - ); - - let implicitly_unstable_manifest = br#" - [package] - name = "test" - version = "0.1.0" - "#; - verify_package_stability_for_manifest( - implicitly_unstable_manifest, - PackageStability::Unstable, - ); - } } diff --git a/tools/ci-build/publisher/src/subcommand/fix_manifests/validate.rs b/tools/ci-build/publisher/src/subcommand/fix_manifests/validate.rs index e99241245..673a91770 100644 --- a/tools/ci-build/publisher/src/subcommand/fix_manifests/validate.rs +++ b/tools/ci-build/publisher/src/subcommand/fix_manifests/validate.rs @@ -5,62 +5,10 @@ use crate::fs::Fs; use crate::package::discover_and_validate_package_batches; -use crate::subcommand::fix_manifests::Versions; -use anyhow::{anyhow, bail, Result}; -use semver::Version; -use smithy_rs_tool_common::package::PackageCategory; +use anyhow::Result; use std::path::Path; use tracing::info; -/// Validations that run before the manifests are fixed. -/// -/// For now, this validates: -/// - `aws-smithy-` prefixed versions match `aws-` (NOT `aws-sdk-`) prefixed versions -pub(super) fn validate_before_fixes( - versions: &Versions, - disable_version_number_validation: bool, -) -> Result<()> { - // Later when we only generate independently versioned SDK crates, this flag can become permanent. - if disable_version_number_validation { - return Ok(()); - } - - info!("Pre-validation manifests..."); - - let expected_stable_runtime_version = versions - .get("aws-smithy-types") - .ok_or_else(|| anyhow!("`aws-smithy-types` crate missing"))?; - - let expected_unstable_runtime_version = versions - .get("aws-smithy-http") - .ok_or_else(|| anyhow!("`aws-smithy-http` crate missing"))?; - - for (name, version) in versions.published_crates() { - let category = PackageCategory::from_package_name(name); - if category == PackageCategory::SmithyRuntime || category == PackageCategory::AwsRuntime { - let expected_runtime_version = if let Some(true) = versions.stable(name) { - expected_stable_runtime_version - } else { - expected_unstable_runtime_version - }; - confirm_version(name, expected_runtime_version, version)?; - } - } - Ok(()) -} - -fn confirm_version(name: &str, expected: &Version, actual: &Version) -> Result<()> { - if expected != actual { - bail!( - "Crate named `{}` should be at version `{}` but is at `{}`", - name, - expected, - actual - ); - } - Ok(()) -} - /// Validations that run after fixing the manifests. /// /// These should match the validations that the `publish` subcommand runs. @@ -69,95 +17,3 @@ pub(super) async fn validate_after_fixes(location: &Path) -> Result<()> { discover_and_validate_package_batches(Fs::Real, location).await?; Ok(()) } - -#[cfg(test)] -mod test { - use super::*; - use crate::subcommand::fix_manifests::VersionWithMetadata; - use smithy_rs_tool_common::package::PackageStability; - use std::collections::BTreeMap; - use std::str::FromStr; - - fn versions(versions: &[(&'static str, &'static str, PackageStability)]) -> Versions { - let mut map = BTreeMap::new(); - for (name, version, stability) in versions { - map.insert( - (*name).into(), - VersionWithMetadata { - version: Version::from_str(version).unwrap(), - publish: true, - stability: *stability, - }, - ); - } - Versions(map) - } - - #[track_caller] - fn expect_success(version_tuples: &[(&'static str, &'static str, PackageStability)]) { - validate_before_fixes(&versions(version_tuples), false).expect("success"); - } - - #[track_caller] - fn expect_failure( - message: &str, - version_tuples: &[(&'static str, &'static str, PackageStability)], - ) { - if let Err(err) = validate_before_fixes(&versions(version_tuples), false) { - assert_eq!(message, format!("{}", err)); - } else { - panic!("Expected validation failure"); - } - } - - #[test] - fn pre_validate() { - expect_success(&[ - ("aws-config", "1.5.2", PackageStability::Stable), - ("aws-smithy-http", "0.35.1", PackageStability::Unstable), - ("aws-sdk-s3", "1.5.2", PackageStability::Stable), - ("aws-smithy-types", "1.5.2", PackageStability::Stable), - ("aws-types", "1.5.2", PackageStability::Stable), - ]); - - expect_success(&[ - ("aws-smithy-types", "1.5.2", PackageStability::Stable), - ("aws-smithy-http", "0.35.1", PackageStability::Unstable), - ]); - - expect_failure( - "Crate named `aws-smithy-runtime-api` should be at version `1.5.3` but is at `1.5.2`", - &[ - ("aws-smithy-runtime-api", "1.5.2", PackageStability::Stable), - ("aws-smithy-types", "1.5.3", PackageStability::Stable), - ("aws-smithy-http", "0.35.0", PackageStability::Unstable), - ], - ); - - expect_success(&[ - ("aws-config", "1.5.2", PackageStability::Stable), - ("aws-smithy-http", "0.35.0", PackageStability::Unstable), - ("aws-sdk-s3", "1.5.2", PackageStability::Stable), - ("aws-smithy-types", "1.5.2", PackageStability::Stable), - ("aws-types", "1.5.2", PackageStability::Stable), - ]); - - expect_failure( - "Crate named `aws-types` should be at version `1.5.3` but is at `1.5.2`", - &[ - ("aws-config", "1.5.3", PackageStability::Stable), - ("aws-sdk-s3", "1.5.3", PackageStability::Stable), - ("aws-smithy-http", "0.35.0", PackageStability::Unstable), - ("aws-smithy-types", "1.5.3", PackageStability::Stable), - ("aws-types", "1.5.2", PackageStability::Stable), - ], - ); - - expect_success(&[ - ("aws-config", "1.5.3", PackageStability::Stable), - ("aws-sdk-s3", "1.5.3", PackageStability::Stable), - ("aws-smithy-types", "1.5.3", PackageStability::Stable), - ("aws-smithy-http", "0.35.0", PackageStability::Unstable), - ]); - } -} diff --git a/tools/ci-build/publisher/src/subcommand/publish.rs b/tools/ci-build/publisher/src/subcommand/publish.rs index 4a8090de0..788f579e8 100644 --- a/tools/ci-build/publisher/src/subcommand/publish.rs +++ b/tools/ci-build/publisher/src/subcommand/publish.rs @@ -9,7 +9,6 @@ use crate::package::{ PackageHandle, PackageStats, }; use crate::publish::{publish, CRATES_IO_CLIENT}; -use crate::retry::{run_with_retry, BoxError, ErrorClass}; use crate::{cargo, SDK_REPO_CRATE_PATH, SDK_REPO_NAME}; use anyhow::{bail, Context, Result}; use clap::Parser; @@ -17,6 +16,7 @@ use crates_io_api::Error; use dialoguer::Confirm; use smithy_rs_tool_common::git; use smithy_rs_tool_common::package::PackageCategory; +use smithy_rs_tool_common::retry::{run_with_retry, BoxError, ErrorClass}; use smithy_rs_tool_common::shell::ShellOperation; use std::collections::HashSet; use std::path::{Path, PathBuf}; diff --git a/tools/ci-build/publisher/src/yank.rs b/tools/ci-build/publisher/src/yank.rs index fa46919a1..8535c5384 100644 --- a/tools/ci-build/publisher/src/yank.rs +++ b/tools/ci-build/publisher/src/yank.rs @@ -4,7 +4,7 @@ */ use crate::cargo; -use crate::retry::{run_with_retry, BoxError, ErrorClass}; +use smithy_rs_tool_common::retry::{run_with_retry, BoxError, ErrorClass}; use smithy_rs_tool_common::shell::ShellOperation; use std::time::Duration; use tracing::info; diff --git a/tools/ci-build/runtime-versioner/Cargo.lock b/tools/ci-build/runtime-versioner/Cargo.lock new file mode 100644 index 000000000..f73ff75a9 --- /dev/null +++ b/tools/ci-build/runtime-versioner/Cargo.lock @@ -0,0 +1,1635 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "crates-index" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f3e3ef6d547bbf1213b3dabbf0b01a500fbd0924abf818b563a4bc2c85296c" +dependencies = [ + "hex", + "home", + "http", + "memchr", + "rustc-hash", + "semver", + "serde", + "serde_derive", + "serde_json", + "smol_str", + "thiserror", + "toml 0.8.8", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[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 = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "proc-macro2" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "runtime-versioner" +version = "0.1.0" +dependencies = [ + "anyhow", + "camino", + "clap", + "crates-index", + "reqwest", + "smithy-rs-tool-common", + "tempfile", + "test-common", + "toml 0.5.11", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "smithy-rs-tool-common" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "lazy_static", + "regex", + "reqwest", + "semver", + "serde", + "serde_json", + "thiserror", + "toml 0.5.11", + "tracing", +] + +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "test-common" +version = "0.1.0" +dependencies = [ + "camino", + "tempfile", + "test_bin", +] + +[[package]] +name = "test_bin" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7a7de15468c6e65dd7db81cf3822c1ec94c71b2a3c1a976ea8e4696c91115c" + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +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.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2 0.5.5", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "indexmap 1.9.3", + "serde", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-bidi" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" + +[[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.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] diff --git a/tools/ci-build/runtime-versioner/Cargo.toml b/tools/ci-build/runtime-versioner/Cargo.toml new file mode 100644 index 000000000..15a356eb0 --- /dev/null +++ b/tools/ci-build/runtime-versioner/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "runtime-versioner" +version = "0.1.0" +authors = ["AWS Rust SDK Team "] +description = "Tool that manages runtime crate versions." +edition = "2021" +license = "Apache-2.0" +publish = false + +[workspace] + +[profile.release] +# prefer fast compile time over runtime performance +opt-level = 0 + +[dependencies] +anyhow = "1.0.75" +camino = "1.1.6" +clap = { version = "4.4.11", features = ["derive"] } +crates-index = "2.3.0" +reqwest = { version = "0.11.22", features = ["blocking"] } +smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common" } +tempfile = "3.9.0" +toml = { version = "0.5.8", features = ["preserve_order"] } +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } + +[dev-dependencies] +test-common = { path = "./test-common" } diff --git a/tools/ci-build/runtime-versioner/src/audit.rs b/tools/ci-build/runtime-versioner/src/audit.rs new file mode 100644 index 000000000..723963372 --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/audit.rs @@ -0,0 +1,259 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::{ + index::CratesIndex, + repo::Repo, + tag::{previous_release_tag, release_tags}, + util::utf8_path_buf, + Audit, +}; +use anyhow::{anyhow, bail, Context, Result}; +use camino::{Utf8Path, Utf8PathBuf}; +use smithy_rs_tool_common::{command::sync::CommandExt, release_tag::ReleaseTag}; +use std::{ + collections::{BTreeMap, BTreeSet}, + fs, + process::Command, +}; + +pub fn audit(args: Audit) -> Result<()> { + let repo = Repo::new(args.smithy_rs_path.as_deref())?; + if !args.no_fetch { + // Make sure we have the latest release tags + fetch_smithy_rs_tags(&repo)?; + } + + let release_tags = release_tags(&repo)?; + let previous_release_tag = + previous_release_tag(&repo, &release_tags, args.previous_release_tag.as_deref())?; + if release_tags.first() != Some(&previous_release_tag) { + tracing::warn!("there are newer releases since '{previous_release_tag}'"); + } + + let next_crates = discover_runtime_crates(&repo.root).context("next")?; + let previous_crates = resolve_previous_crates(&repo, previous_release_tag.as_str())?; + + let crates = augment_runtime_crates(previous_crates, next_crates, args.fake_crates_io_index)?; + let mut errors = Vec::new(); + for rt_crate in crates { + if let Err(err) = audit_crate(&repo, &previous_release_tag, rt_crate) { + errors.push(err); + } + } + if errors.is_empty() { + println!("SUCCESS"); + Ok(()) + } else { + for error in errors { + eprintln!("{error}"); + } + bail!("there are audit failures in the runtime crates") + } +} + +fn audit_crate(repo: &Repo, release_tag: &ReleaseTag, rt_crate: RuntimeCrate) -> Result<()> { + if rt_crate.changed_since_release(repo, release_tag)? { + // If this version has never been published before, then we're good. + // (This tool doesn't check semver compatibility.) + if !rt_crate.next_version_is_published() { + if let Some(previous_version) = rt_crate.previous_release_version { + tracing::info!( + "'{}' changed and was version bumped from {previous_version} to {}", + rt_crate.name, + rt_crate.next_release_version, + ); + } else { + tracing::info!( + "'{}' is a new crate (or wasn't independently versioned before) and will publish at {}", + rt_crate.name, + rt_crate.next_release_version, + ); + } + Ok(()) + } else if rt_crate.previous_release_version.as_ref() != Some(&rt_crate.next_release_version) + { + Err(anyhow!( + "{crate_name} was changed and version bumped, but the new version \ + number ({version}) has already been published to crates.io. Choose a new \ + version number.", + crate_name = rt_crate.name, + version = rt_crate.next_release_version, + )) + } else { + Err(anyhow!( + "{crate_name} changed since {release_tag} and requires a version bump", + crate_name = rt_crate.name + )) + } + } else { + // If it didn't change at all since last release, then we're good. + Ok(()) + } +} + +struct RuntimeCrate { + name: String, + path: Utf8PathBuf, + previous_release_version: Option, + next_release_version: String, + published_versions: Vec, +} + +impl RuntimeCrate { + /// True if the runtime crate's next version exists in crates.io + fn next_version_is_published(&self) -> bool { + self.published_versions + .iter() + .any(|version| self.next_release_version == *version) + } + + /// True if this runtime crate changed since the given release tag. + fn changed_since_release(&self, repo: &Repo, release_tag: &ReleaseTag) -> Result { + let status = repo + .git(["diff", "--quiet", release_tag.as_str(), self.path.as_str()]) + .status() + .with_context(|| format!("failed to git diff {}", self.name))?; + match status.code() { + Some(0) => Ok(false), + Some(1) => Ok(true), + code => bail!("unknown git diff result: {code:?}"), + } + } +} + +/// Loads version information from crates.io and attaches it to the passed in runtime crates. +fn augment_runtime_crates( + previous_crates: BTreeMap, + next_crates: BTreeMap, + fake_crates_io_index: Option, +) -> Result> { + let index = fake_crates_io_index + .map(CratesIndex::fake) + .map(Ok) + .unwrap_or_else(CratesIndex::real)?; + let all_keys: BTreeSet<_> = previous_crates.keys().chain(next_crates.keys()).collect(); + let mut result = Vec::new(); + for key in all_keys { + let previous_crate = previous_crates.get(key); + if let Some(next_crate) = next_crates.get(key) { + result.push(RuntimeCrate { + published_versions: index.published_versions(&next_crate.name)?, + name: next_crate.name.clone(), + previous_release_version: previous_crate.map(|c| c.version.clone()), + next_release_version: next_crate.version.clone(), + path: next_crate.path.clone(), + }); + } else { + tracing::warn!("runtime crate '{key}' was removed and will not be published"); + } + } + Ok(result) +} + +struct DiscoveredCrate { + name: String, + version: String, + path: Utf8PathBuf, +} + +/// Discovers runtime crates that are independently versioned. +/// For now, that just means the ones that don't have the special version number `0.0.0-smithy-rs-head`. +/// In the future, this can be simplified to just return all the runtime crates. +fn discover_runtime_crates(repo_root: &Utf8Path) -> Result> { + const ROOT_PATHS: &[&str] = &["rust-runtime", "aws/rust-runtime"]; + let mut result = BTreeMap::new(); + for &root in ROOT_PATHS { + let root = repo_root.join(root); + for entry in fs::read_dir(&root) + .context(root) + .context("failed to read dir")? + { + let entry = entry.context("failed to read dir entry")?; + if !entry.path().is_dir() { + continue; + } + let manifest_path = entry.path().join("Cargo.toml"); + if !manifest_path.exists() { + continue; + } + let manifest: toml::Value = + toml::from_slice(&fs::read(&manifest_path).context("failed to read manifest")?) + .context("failed to parse manifest")?; + let publish = manifest["package"] + .get("publish") + .and_then(|p| p.as_bool()) + .unwrap_or(true); + let version = manifest["package"]["version"] + .as_str() + .expect("version is a string"); + if publish && version != "0.0.0-smithy-rs-head" { + let name: String = entry.path().file_name().unwrap().to_string_lossy().into(); + result.insert( + name.clone(), + DiscoveredCrate { + name, + version: version.into(), + path: utf8_path_buf(entry.path()), + }, + ); + } + } + } + Ok(result) +} + +fn resolve_previous_crates( + repo: &Repo, + previous_release_tag: &str, +) -> Result> { + // We checkout to a temp path so that this can be run with a dirty working tree + // (for running in local development). + let tempdir = tempfile::tempdir()?; + let tempdir_path = Utf8Path::from_path(tempdir.path()).unwrap(); + let clone_path = tempdir_path.join("smithy-rs"); + fs::create_dir_all(&clone_path).context("failed to create temp smithy-rs repo")?; + + checkout_runtimes_to(repo, previous_release_tag, &clone_path) + .context("resolve previous crates")?; + discover_runtime_crates(&clone_path).context("resolve previous crates") +} + +/// Fetches the latest tags from smithy-rs origin. +fn fetch_smithy_rs_tags(repo: &Repo) -> Result<()> { + let output = repo + .git(["remote", "get-url", "origin"]) + .output() + .context("failed to verify origin git remote")?; + let origin_url = String::from_utf8(output.stdout) + .expect("valid utf-8") + .trim() + .to_string(); + if origin_url != "git@github.com:smithy-lang/smithy-rs.git" { + bail!("smithy-rs origin must be 'git@github.com:smithy-lang/smithy-rs.git' in order to get the latest release tags"); + } + + repo.git(["fetch", "--tags", "origin"]) + .expect_success_output("fetch tags")?; + Ok(()) +} + +fn checkout_runtimes_to(repo: &Repo, revision: &str, into: impl AsRef) -> Result<()> { + Command::new("git") + .arg("init") + .current_dir(into.as_ref()) + .expect_success_output("init")?; + let tmp_repo = Repo::new(Some(into.as_ref()))?; + tmp_repo + .git(["remote", "add", "origin", repo.root.as_str()]) + .expect_success_output("remote add origin")?; + tmp_repo + .git(["fetch", "origin", revision, "--depth", "1"]) + .expect_success_output("fetch revision")?; + tmp_repo + .git(["reset", "--hard", "FETCH_HEAD"]) + .expect_success_output("reset")?; + Ok(()) +} diff --git a/tools/ci-build/runtime-versioner/src/index.rs b/tools/ci-build/runtime-versioner/src/index.rs new file mode 100644 index 000000000..41106ef7b --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/index.rs @@ -0,0 +1,109 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use anyhow::{anyhow, Context, Error, Result}; +use camino::Utf8Path; +use crates_index::Crate; +use reqwest::StatusCode; +use smithy_rs_tool_common::retry::{run_with_retry_sync, ErrorClass}; +use std::fs; +use std::{collections::HashMap, time::Duration}; + +pub struct CratesIndex(Inner); + +enum Inner { + Fake(FakeIndex), + Real(crates_index::SparseIndex), +} + +impl CratesIndex { + /// Returns a real sparse crates.io index. + pub fn real() -> Result { + Ok(Self(Inner::Real( + crates_index::SparseIndex::new_cargo_default() + .context("failed to initialize the sparse crates.io index")?, + ))) + } + + /// Returns a fake crates.io index from file, panicking if loading fails. + pub fn fake(path: impl AsRef) -> Self { + Self(Inner::Fake(FakeIndex::from_file(path))) + } + + /// Retrieves the published versions for the given crate name. + pub fn published_versions(&self, crate_name: &str) -> Result> { + match &self.0 { + Inner::Fake(index) => Ok(index.crates.get(crate_name).cloned().unwrap_or_default()), + Inner::Real(index) => Ok(run_with_retry_sync( + "retrieve published versions", + 3, + Duration::from_secs(1), + || published_versions(index, crate_name), + |_err| ErrorClass::Retry, + )?), + } + } +} + +fn published_versions(index: &crates_index::SparseIndex, crate_name: &str) -> Result> { + let url = index + .crate_url(crate_name) + .expect("crate name is not empty string"); + let crate_meta: Option = reqwest::blocking::get(url) + .map_err(Error::from) + .and_then(|response| { + let status = response.status(); + response.bytes().map(|b| (status, b)).map_err(Error::from) + }) + .and_then(|(status, bytes)| match status { + status if status.is_success() => { + Crate::from_slice(&bytes).map_err(Error::from).map(Some) + } + StatusCode::NOT_FOUND => Ok(None), + status => { + let body = String::from_utf8_lossy(&bytes); + Err(anyhow!( + "request to crates.io index failed ({status}):\n{body}" + )) + } + }) + .with_context(|| format!("failed to retrieve crates.io metadata for {crate_name}"))?; + Ok(crate_meta + .map(|meta| { + meta.versions() + .iter() + .map(|v| v.version().to_string()) + .collect() + }) + .unwrap_or_default()) +} + +/// Fake crates.io index for testing +pub struct FakeIndex { + crates: HashMap>, +} + +impl FakeIndex { + fn from_file(path: impl AsRef) -> FakeIndex { + let bytes = fs::read(path.as_ref()).unwrap(); + let toml: toml::Value = toml::from_slice(&bytes).unwrap(); + let crates: HashMap> = toml["crates"] + .as_table() + .expect("missing crates table") + .into_iter() + .map(|(k, v)| { + ( + k.into(), + v.as_array() + .expect("value must be array") + .iter() + .map(|v| v.as_str().expect("must be string").to_string()) + .collect::>(), + ) + }) + .collect(); + FakeIndex { crates } + } +} diff --git a/tools/ci-build/runtime-versioner/src/main.rs b/tools/ci-build/runtime-versioner/src/main.rs new file mode 100644 index 000000000..e09951f04 --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/main.rs @@ -0,0 +1,82 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::{ + repo::Repo, + tag::{previous_release_tag, release_tags}, +}; +use anyhow::Result; +use camino::Utf8PathBuf; +use clap::Parser; +use tracing_subscriber::{filter::LevelFilter, EnvFilter}; + +mod audit; +mod index; +mod repo; +mod tag; +mod util; + +#[derive(clap::Args, Clone)] +pub struct Audit { + /// Don't `git fetch` before auditing. + #[arg(long)] + no_fetch: bool, + /// Explicitly state the previous release's tag. Discovers it if not provided. + #[arg(long)] + previous_release_tag: Option, + /// Path to smithy-rs. Defaults to current working directory. + #[arg(long)] + smithy_rs_path: Option, + /// (For testing) Path to a fake crates.io index. + #[arg(long)] + fake_crates_io_index: Option, +} + +#[derive(clap::Args, Clone)] +pub struct PreviousReleaseTag { + /// Path to smithy-rs. Defaults to current working directory. + #[arg(long)] + smithy_rs_path: Option, +} + +#[derive(clap::Parser, Clone)] +#[clap(author, version, about)] +enum Command { + /// Audit the runtime crate versions in the smithy-rs repo at HEAD + /// + /// Requires a full clone of smithy-rs. Will not work against shallow clones. + /// + /// This audits that any runtime crate that has been changed since the last + /// release has been version bumped. It's not smart enough to know if the version + /// bump is correct in semver terms, but verifies that there was at least a + /// bump. A human will still need to verify the semver correctness of that bump. + Audit(Audit), + + /// Outputs the previous release tag for the revision at HEAD. + PreviousReleaseTag(PreviousReleaseTag), +} + +fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_writer(std::io::stderr) + .with_env_filter( + EnvFilter::builder() + .with_default_directive(LevelFilter::INFO.into()) + .from_env_lossy(), + ) + .init(); + + let command = Command::parse(); + match command { + Command::Audit(args) => audit::audit(args), + Command::PreviousReleaseTag(args) => { + let repo = Repo::new(args.smithy_rs_path.as_deref())?; + let tags = release_tags(&repo)?; + let tag = previous_release_tag(&repo, &tags, None)?; + println!("{tag}"); + Ok(()) + } + } +} diff --git a/tools/ci-build/runtime-versioner/src/repo.rs b/tools/ci-build/runtime-versioner/src/repo.rs new file mode 100644 index 000000000..45290368a --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/repo.rs @@ -0,0 +1,43 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::util::utf8_path_buf; +use anyhow::{Context, Result}; +use camino::{Utf8Path, Utf8PathBuf}; +use smithy_rs_tool_common::git::find_git_repository_root; +use std::{env, ffi::OsStr, process::Command}; + +/// Git repository +pub struct Repo { + pub root: Utf8PathBuf, +} + +impl Repo { + pub fn new(maybe_root: Option<&Utf8Path>) -> Result { + Ok(Self { + root: repo_root(maybe_root)?, + }) + } + + /// Returns a `std::process::Command` set to run git in this repo with the given args + pub fn git(&self, args: I) -> Command + where + I: IntoIterator, + S: AsRef, + { + let mut cmd = Command::new("git"); + cmd.current_dir(&self.root); + cmd.args(args); + cmd + } +} + +fn repo_root(hint: Option<&Utf8Path>) -> Result { + let cwd = utf8_path_buf(env::current_dir().context("failed to get current working directory")?); + Ok(utf8_path_buf(find_git_repository_root( + "smithy-rs", + hint.unwrap_or(&cwd), + )?)) +} diff --git a/tools/ci-build/runtime-versioner/src/tag.rs b/tools/ci-build/runtime-versioner/src/tag.rs new file mode 100644 index 000000000..def5b6d63 --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/tag.rs @@ -0,0 +1,120 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::repo::Repo; +use anyhow::{anyhow, bail, Context, Result}; +use smithy_rs_tool_common::{command::sync::CommandExt, release_tag::ReleaseTag}; +use std::str::FromStr; +use tracing::warn; + +/// Discovers and returns the tag of the previous release for the revision at HEAD. +pub fn previous_release_tag( + repo: &Repo, + release_tags: &[ReleaseTag], + release_tag_override: Option<&str>, +) -> Result { + let ancestor_tag = ancestor_tag(repo)?; + let tag_override = release_tag_override + .map(ReleaseTag::from_str) + .transpose() + .context("invalid release tag given")?; + if let Some(tag_override) = tag_override { + if !release_tags.contains(&tag_override) { + bail!("specified tag '{tag_override}' doesn't exist"); + } + if !tag_is_ancestor(repo, &tag_override)? { + bail!("specified tag '{tag_override}' is not an ancestor to HEAD"); + } + if tag_override != ancestor_tag { + warn!( + "expected previous release to be '{ancestor_tag}', \ + but '{tag_override}' was specified. Proceeding with '{tag_override}'.", + ); + } + Ok(tag_override) + } else { + Ok(ancestor_tag) + } +} + +fn ancestor_tag(repo: &Repo) -> Result { + let tag = repo + .git(["describe", "--tags"]) + .expect_success_output("find the current ancestor release tag")?; + let maybe_release_tag = ReleaseTag::from_str(&tag); + let release_tag = match maybe_release_tag { + Ok(tag) => Some(tag), + Err(_) => strip_describe_tags_suffix(&tag) + .map(ReleaseTag::from_str) + .transpose() + .context("failed to find ancestor release tag")?, + }; + release_tag.ok_or_else(|| anyhow!("failed to find ancestor release tag")) +} + +// `git describe --tags` appends a suffix if the current commit is not the tagged commit +// +// Function assumes the given tag is known to be suffixed. +fn strip_describe_tags_suffix(tag: &str) -> Option<&str> { + // Example release tag with suffix: release-2023-12-01-42-g885048e40 + tag.rsplitn(3, '-').nth(2) +} + +/// Returns all release tags for the repo in descending order by time. +pub fn release_tags(repo: &Repo) -> Result> { + let mut tags: Vec<_> = repo + .git(["tag"]) + .expect_success_output("find the current ancestor release tag")? + .lines() + .flat_map(|tag| match ReleaseTag::from_str(tag) { + Ok(tag) => Some(tag), + Err(_) => { + if !tag.starts_with("v0.") { + warn!("ignoring tag '{tag}': doesn't look like a release tag"); + } + None + } + }) + .collect(); + tags.sort_by(|a, b| b.cmp(a)); + Ok(tags) +} + +/// True if the given tag is an ancestor to HEAD. +fn tag_is_ancestor(repo: &Repo, tag: &ReleaseTag) -> Result { + let commit = commit_for_tag(repo, tag)?; + let status = repo + .git(["merge-base", "--is-ancestor", &commit, "HEAD"]) + .expect_status_one_of("determine if a tag is the ancestor to HEAD", [0, 1])?; + Ok(status == 0) +} + +/// Returns the commit hash for the given tag +fn commit_for_tag(repo: &Repo, tag: &ReleaseTag) -> Result { + repo.git(["rev-list", "-n1", tag.as_str()]) + .expect_success_output("retrieve commit hash for tag") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn strip_git_describe_tags_suffix() { + assert_eq!( + Some("release-2023-12-01"), + strip_describe_tags_suffix("release-2023-12-01-42-g885048e40") + ); + assert_eq!( + Some("release-2023-12-01"), + strip_describe_tags_suffix("release-2023-12-01-2-g885048e40") + ); + assert_eq!( + Some("release-2023-12-01"), + strip_describe_tags_suffix("release-2023-12-01-123-g885048e40") + ); + assert_eq!(None, strip_describe_tags_suffix("invalid")); + } +} diff --git a/tools/ci-build/runtime-versioner/src/util.rs b/tools/ci-build/runtime-versioner/src/util.rs new file mode 100644 index 000000000..61426ab9e --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/util.rs @@ -0,0 +1,16 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use anyhow::Context; +use camino::{Utf8Path, Utf8PathBuf}; +use std::path::Path; + +pub fn utf8_path_buf(path: impl AsRef) -> Utf8PathBuf { + let path: &Path = path.as_ref(); + <&Utf8Path>::try_from(path) + .with_context(|| format!("gross path_buf: {:?}", path)) + .unwrap() + .into() +} diff --git a/tools/ci-build/runtime-versioner/test-common/Cargo.toml b/tools/ci-build/runtime-versioner/test-common/Cargo.toml new file mode 100644 index 000000000..e23fab820 --- /dev/null +++ b/tools/ci-build/runtime-versioner/test-common/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "test-common" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +camino = "1.1.6" +tempfile = "3.8.1" +test_bin = "0.4.0" diff --git a/tools/ci-build/runtime-versioner/test-common/src/lib.rs b/tools/ci-build/runtime-versioner/test-common/src/lib.rs new file mode 100644 index 000000000..7f151cb88 --- /dev/null +++ b/tools/ci-build/runtime-versioner/test-common/src/lib.rs @@ -0,0 +1,100 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use camino::{Utf8Path, Utf8PathBuf}; +use std::process::Command; +use tempfile::TempDir; + +#[derive(Debug)] +pub struct VersionerOutput { + pub status: i32, + pub stdout: String, + pub stderr: String, +} + +pub struct TestBase { + _tmp: TempDir, + pub test_data: Utf8PathBuf, + pub root: Utf8PathBuf, +} + +impl TestBase { + pub fn new(branch_name: &str) -> Self { + let tmp = TempDir::new().unwrap(); + let root = Utf8PathBuf::try_from(tmp.path().join("test_base")).unwrap(); + + let test_data = + Utf8PathBuf::try_from(std::env::current_dir().unwrap().join("test_data")).unwrap(); + let tar_path = test_data.join("test_base.git.tar.gz"); + assert!( + Command::new("tar") + .args(["xfz", tar_path.as_str()]) + .current_dir(tmp.path()) + .status() + .unwrap() + .success(), + "untarring the test_base into the temp directory failed" + ); + assert!( + Command::new("git") + .args(["clone", "test_base.git"]) + .current_dir(tmp.path()) + .status() + .unwrap() + .success(), + "cloning the test_base repo failed" + ); + assert!(root.exists(), "test_base not found after cloning"); + change_branch(&root, branch_name); + + Self { + _tmp: tmp, + test_data, + root, + } + } + + pub fn change_branch(&self, branch_name: &str) { + change_branch(&self.root, branch_name); + } + + pub fn run_versioner(&self, args: &[&str], expect_failure: bool) -> VersionerOutput { + let mut cmd = test_bin::get_test_bin("runtime-versioner"); + let cmd = cmd.args(args).current_dir(&self.root); + let output = cmd.output().expect("failed to execute runtime-versioner"); + let status = output.status.code().unwrap(); + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + println!("###\ncmd: {cmd:?}\nstatus: {status}\nstdout:\n{stdout}\nstderr:\n{stderr}\n\n"); + if expect_failure { + assert!( + !output.status.success(), + "expected runtime-versioner to fail, but it succeeded" + ); + } else { + assert!( + output.status.success(), + "expected runtime-versioner to succeed, but it failed" + ); + } + VersionerOutput { + status, + stdout: stdout.into(), + stderr: stderr.into(), + } + } +} + +fn change_branch(path: &Utf8Path, branch_name: &str) { + assert!( + Command::new("git") + .args(["checkout", branch_name]) + .current_dir(path) + .status() + .unwrap() + .success(), + "changing to the correct test_base branch failed" + ); +} diff --git a/tools/ci-build/runtime-versioner/test_data/.gitignore b/tools/ci-build/runtime-versioner/test_data/.gitignore new file mode 100644 index 000000000..61f335ae7 --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/.gitignore @@ -0,0 +1,2 @@ +/test_base.git/ +/test_base/ \ No newline at end of file diff --git a/tools/ci-build/runtime-versioner/test_data/Makefile b/tools/ci-build/runtime-versioner/test_data/Makefile new file mode 100644 index 000000000..5419b47ef --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/Makefile @@ -0,0 +1,22 @@ +all: + echo "Use the pack/unpack targets." + +# Unpacks test_base.git.tar.gz +# +# Note: doesn't directly clone the bare repository into a working tree, +# or otherwise it would lose all the different branches. +unpack: + rm -rf test_base + mkdir -p test_base + tar xfz test_base.git.tar.gz + mv test_base.git test_base/.git + (cd test_base && git config --unset core.bare) + (cd test_base && git reset --hard) + +# Packs test_base.git.tar.gz +pack: + git clone --bare test_base + tar cfz test_base.git.tar.gz test_base.git + rm -rf test_base.git + +.PHONY: all \ No newline at end of file diff --git a/tools/ci-build/runtime-versioner/test_data/README.md b/tools/ci-build/runtime-versioner/test_data/README.md new file mode 100644 index 000000000..b156de76c --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/README.md @@ -0,0 +1,14 @@ +Test base archive +================= + +The `test_base.git.tar.gz` is an archived test git repository that looks like a +smithy-rs repo (with only the runtime crates), with some version numbers and +release tags. + +It is a bare git repository (no working tree). To modify it, use the Makefile in +this directory to unpack it with `make unpack`. This will create a test_base directory +in test_data where you can make any changes you need to the repo. Then running +`make pack` will convert that modified repository back into the archive. + +When making new test cases that need some extensive setup, it's best to create +a test-case specific branch in the test base. \ No newline at end of file diff --git a/tools/ci-build/runtime-versioner/test_data/already_published_version.toml b/tools/ci-build/runtime-versioner/test_data/already_published_version.toml new file mode 100644 index 000000000..0d65a32f3 --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/already_published_version.toml @@ -0,0 +1,28 @@ +[crates] +aws-config = ["1.0.0"] +aws-endpoint = ["0.60.0"] +aws-http = ["0.60.0"] +aws-hyper = ["0.60.0"] +aws-runtime = ["1.0.0"] +aws-runtime-api = ["1.0.0"] +aws-sig-auth = ["0.60.0"] +aws-sigv4 = ["1.0.0"] +aws-smithy-async = ["1.0.1"] # Oh no, aws-smithy-async already has 1.0.1 published! +aws-smithy-checksums = ["0.60.0"] +aws-smithy-client = ["0.60.0"] +aws-smithy-eventstream = ["0.60.0"] +aws-smithy-http = ["0.60.0"] +aws-smithy-http-auth = ["0.60.0"] +aws-smithy-http-server = ["0.60.0"] +aws-smithy-http-server-python = ["0.60.0"] +aws-smithy-http-server-typescript = ["0.60.0"] +aws-smithy-http-tower = ["0.60.0"] +aws-smithy-json = ["0.60.0"] +aws-smithy-protocol-test = ["0.60.0"] +aws-smithy-query = ["0.60.0"] +aws-smithy-runtime = ["1.0.0"] +aws-smithy-runtime-api = ["1.0.0"] +aws-smithy-types = ["1.0.0"] +aws-smithy-types-convert = ["0.60.0"] +aws-smithy-xml = ["0.60.0"] +aws-types = ["1.0.0"] diff --git a/tools/ci-build/runtime-versioner/test_data/base_crates_io_index.toml b/tools/ci-build/runtime-versioner/test_data/base_crates_io_index.toml new file mode 100644 index 000000000..70de8ec50 --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/base_crates_io_index.toml @@ -0,0 +1,28 @@ +[crates] +aws-config = ["1.0.0"] +aws-endpoint = ["0.60.0"] +aws-http = ["0.60.0"] +aws-hyper = ["0.60.0"] +aws-runtime = ["1.0.0"] +aws-runtime-api = ["1.0.0"] +aws-sig-auth = ["0.60.0"] +aws-sigv4 = ["1.0.0"] +aws-smithy-async = ["1.0.0"] +aws-smithy-checksums = ["0.60.0"] +aws-smithy-client = ["0.60.0"] +aws-smithy-eventstream = ["0.60.0"] +aws-smithy-http = ["0.60.0"] +aws-smithy-http-auth = ["0.60.0"] +aws-smithy-http-server = ["0.60.0"] +aws-smithy-http-server-python = ["0.60.0"] +aws-smithy-http-server-typescript = ["0.60.0"] +aws-smithy-http-tower = ["0.60.0"] +aws-smithy-json = ["0.60.0"] +aws-smithy-protocol-test = ["0.60.0"] +aws-smithy-query = ["0.60.0"] +aws-smithy-runtime = ["1.0.0"] +aws-smithy-runtime-api = ["1.0.0"] +aws-smithy-types = ["1.0.0"] +aws-smithy-types-convert = ["0.60.0"] +aws-smithy-xml = ["0.60.0"] +aws-types = ["1.0.0"] diff --git a/tools/ci-build/runtime-versioner/test_data/test_base.git.tar.gz b/tools/ci-build/runtime-versioner/test_data/test_base.git.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..539485e65d1b9d318e787bedac0387791e4aa742 GIT binary patch literal 49188 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 VersionerOutput { + test_base.run_versioner( + &[ + "audit", + "--no-fetch", + "--fake-crates-io-index", + test_base.test_data.join(index_name).as_str(), + ], + expect_failure, + ) +} + +/// Test that the audit passes when all the runtime crates are at the +/// special `0.0.0-smithy-rs-head` version, indicating not to use +/// independent crate versions. +#[test] +fn all_smithy_rs_head() { + let test_base = TestBase::new("all_smithy_rs_head"); + let result = run_audit(&test_base, "base_crates_io_index.toml", false); + assert!(result.stdout.contains("SUCCESS")); +} + +/// Changing an independently versioned runtime crate and version bumping +/// it to a version that's never been published before succeeds. +#[test] +fn change_crate_with_bump() { + let test_base = TestBase::new("change_crate_with_bump"); + let result = run_audit(&test_base, "base_crates_io_index.toml", false); + assert!(result.stdout.contains("SUCCESS")); +} + +/// Changing an independently versioned runtime crate and version bumping +/// it to a version that's been published before (oops!) fails the audit. +#[test] +fn change_crate_with_bump_to_already_published_version() { + let test_base = TestBase::new("change_crate_with_bump"); + let result = run_audit(&test_base, "already_published_version.toml", true); + assert!(result.stderr.contains( + "aws-smithy-async was changed and version bumped, \ + but the new version number (1.0.1) has already been \ + published to crates.io", + )); +} + +/// Changing an independent runtime crate without version bumping it fails the audit. +#[test] +fn change_crate_without_bump() { + let test_base = TestBase::new("change_crate_without_bump"); + let result = run_audit(&test_base, "base_crates_io_index.toml", true); + assert!(result + .stderr + .contains("aws-smithy-async changed since release-2023-10-02 and requires a version bump")); +} + +/// Adding a new crate that's never been published before passes audit. +#[test] +fn add_new_crate() { + let test_base = TestBase::new("add_new_crate"); + let result = run_audit(&test_base, "base_crates_io_index.toml", false); + assert!(result.stderr.contains("'aws-smithy-newcrate' is a new crate (or wasn't independently versioned before) and will publish at 1.0.0")); + assert!(result.stdout.contains("SUCCESS")); +} + +/// Removing an old crate that's been published before passes audit. +#[test] +fn remove_old_crate() { + let test_base = TestBase::new("remove_old_crate"); + let result = run_audit(&test_base, "base_crates_io_index.toml", false); + assert!(result + .stderr + .contains("runtime crate 'aws-smithy-http' was removed and will not be published")); + assert!(result.stdout.contains("SUCCESS")); +} diff --git a/tools/ci-build/runtime-versioner/tests/test_previous_release_tag.rs b/tools/ci-build/runtime-versioner/tests/test_previous_release_tag.rs new file mode 100644 index 000000000..991bb32d1 --- /dev/null +++ b/tools/ci-build/runtime-versioner/tests/test_previous_release_tag.rs @@ -0,0 +1,25 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use test_common::TestBase; + +#[test] +fn previous_release_tag() { + let test_base = TestBase::new("all_smithy_rs_head"); + assert_eq!( + "release-2023-10-01\n", + test_base + .run_versioner(&["previous-release-tag"], false) + .stdout + ); + + test_base.change_branch("change_crate_with_bump"); + assert_eq!( + "release-2023-10-02\n", + test_base + .run_versioner(&["previous-release-tag"], false) + .stdout + ); +} diff --git a/tools/ci-build/sdk-lints/Cargo.lock b/tools/ci-build/sdk-lints/Cargo.lock index e7cf5dcaa..ae77b7336 100644 --- a/tools/ci-build/sdk-lints/Cargo.lock +++ b/tools/ci-build/sdk-lints/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,28 +19,28 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -62,9 +62,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -77,9 +77,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" @@ -89,21 +89,21 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cargo_toml" @@ -117,9 +117,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -168,9 +171,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -178,15 +181,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -199,30 +202,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fnv" @@ -247,45 +239,45 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-task", @@ -295,15 +287,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" dependencies = [ "bytes", "fnv", @@ -311,7 +303,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -347,9 +339,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -358,9 +350,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -375,15 +367,15 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -418,9 +410,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -448,21 +440,21 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -475,27 +467,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -514,13 +506,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -543,26 +535,26 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -579,7 +571,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -590,9 +582,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" dependencies = [ "cc", "libc", @@ -602,21 +594,21 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -626,9 +618,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "proc-macro-error" @@ -656,36 +648,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -695,9 +687,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -706,15 +698,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "base64", "bytes", @@ -737,6 +729,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -755,30 +748,30 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -819,35 +812,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.176" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.176" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -877,9 +870,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -896,18 +889,19 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "toml 0.5.11", "tracing", ] [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -929,9 +923,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -939,23 +933,44 @@ dependencies = [ ] [[package]] -name = "tempfile" -version = "3.7.0" +name = "system-configuration" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -966,6 +981,26 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -983,18 +1018,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "pin-project-lite", "socket2", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1009,9 +1043,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1073,11 +1107,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1085,41 +1118,41 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -1132,9 +1165,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -1170,9 +1203,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1180,24 +1213,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -1207,9 +1240,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1217,28 +1250,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -1262,9 +1295,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -1281,65 +1314,131 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" @@ -1352,9 +1451,10 @@ dependencies = [ [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] diff --git a/tools/ci-build/sdk-versioner/Cargo.lock b/tools/ci-build/sdk-versioner/Cargo.lock index 5643bfa06..22de949b4 100644 --- a/tools/ci-build/sdk-versioner/Cargo.lock +++ b/tools/ci-build/sdk-versioner/Cargo.lock @@ -40,7 +40,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -567,7 +567,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -660,18 +660,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -845,7 +845,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -892,6 +892,7 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "toml", "tracing", ] @@ -935,9 +936,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -993,6 +994,26 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1099,7 +1120,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1197,7 +1218,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -1231,7 +1252,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/tools/ci-build/smithy-rs-tool-common/Cargo.toml b/tools/ci-build/smithy-rs-tool-common/Cargo.toml index e6e5cded1..def306f5a 100644 --- a/tools/ci-build/smithy-rs-tool-common/Cargo.toml +++ b/tools/ci-build/smithy-rs-tool-common/Cargo.toml @@ -9,7 +9,7 @@ publish = false [workspace] [features] -async-shell = ["tokio"] +async = ["tokio"] [profile.release] # prefer fast compile time over runtime performance @@ -24,6 +24,7 @@ reqwest = "0.11.10" semver = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" +thiserror = "1.0.56" tokio = { version = "1.20.1", features = ["rt", "macros"], optional = true } toml = { version = "0.5.8", features = ["preserve_order"] } tracing = "0.1" diff --git a/tools/ci-build/smithy-rs-tool-common/src/command.rs b/tools/ci-build/smithy-rs-tool-common/src/command.rs new file mode 100644 index 000000000..113014240 --- /dev/null +++ b/tools/ci-build/smithy-rs-tool-common/src/command.rs @@ -0,0 +1,75 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Utilities to simplify working with [`std::command::Command`]. + +/// Synchronous command extension functions. +pub mod sync { + use anyhow::{bail, Context, Result}; + use std::process::Command; + + /// Extension trait to make `Command` nicer to work with. + pub trait CommandExt { + /// Expects the command to exit with a successful status, and returns the command's stdout. + /// + /// If the command fails, the `context` is used to help describe the problem. + /// It will always be formatted with "failed to {context}". + fn expect_success_output(&mut self, context: &str) -> Result; + + /// Expects the command to exit with one of the given statuses. + /// + /// If the command fails, the `context` is used to help describe the problem. + /// It will always be formatted with "failed to {context}". + fn expect_status_one_of( + &mut self, + context: &str, + statuses: impl IntoIterator, + ) -> Result; + } + + impl CommandExt for Command { + fn expect_success_output(&mut self, context: &str) -> Result { + let output = self + .output() + .with_context(|| format!("failed to invoke {:?}", self))?; + let stdout = String::from_utf8(output.stdout) + .with_context(|| format!("command: {:?}", self)) + .context("output had invalid utf-8")?; + if !output.status.success() { + bail!( + "failed to {context}\n\ncommand: {:?}\n\nstdout:\n{}\n\nstderr:\n{}\n", + self, + stdout, + String::from_utf8_lossy(&output.stderr), + ); + } + Ok(stdout) + } + + fn expect_status_one_of( + &mut self, + context: &str, + statuses: impl IntoIterator, + ) -> Result { + let output = self + .output() + .with_context(|| format!("failed to invoke {:?}", self))?; + let expected: Vec<_> = statuses.into_iter().collect(); + let actual = output.status.code().unwrap(); + if expected.contains(&actual) { + Ok(actual) + } else { + bail!( + "failed to {context}\n\n\ + expected exit status to be one of {expected:?}, but got {actual}\n\n\ + command: {:?}\n\nstdout:\n{}\n\nstderr:\n{}\n", + self, + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr), + ) + } + } + } +} diff --git a/tools/ci-build/smithy-rs-tool-common/src/git/get_current_tag.rs b/tools/ci-build/smithy-rs-tool-common/src/git/get_current_tag.rs index 51259358c..4bf88a666 100644 --- a/tools/ci-build/smithy-rs-tool-common/src/git/get_current_tag.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/git/get_current_tag.rs @@ -53,7 +53,7 @@ mod tests { assert_eq!("some-tag", tag); } - #[cfg(feature = "async-shell")] + #[cfg(feature = "async")] #[tokio::test] async fn get_current_tag_success_async() { let tag = GetCurrentTag { diff --git a/tools/ci-build/smithy-rs-tool-common/src/lib.rs b/tools/ci-build/smithy-rs-tool-common/src/lib.rs index 12876e5da..7d2e7083b 100644 --- a/tools/ci-build/smithy-rs-tool-common/src/lib.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/lib.rs @@ -5,10 +5,12 @@ pub mod changelog; pub mod ci; +pub mod command; pub mod git; #[macro_use] pub mod macros; pub mod package; pub mod release_tag; +pub mod retry; pub mod shell; pub mod versions_manifest; diff --git a/tools/ci-build/publisher/src/retry.rs b/tools/ci-build/smithy-rs-tool-common/src/retry.rs similarity index 55% rename from tools/ci-build/publisher/src/retry.rs rename to tools/ci-build/smithy-rs-tool-common/src/retry.rs index 1608da844..fd02e18ec 100644 --- a/tools/ci-build/publisher/src/retry.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/retry.rs @@ -5,7 +5,6 @@ use std::error::Error; use std::error::Error as StdError; -use std::future::Future; use std::time::Duration; use tracing::{error, info}; @@ -24,6 +23,7 @@ pub enum RetryError { FailedMaxAttempts(usize), } +#[cfg(feature = "async")] pub async fn run_with_retry( what: &str, max_attempts: usize, @@ -33,7 +33,7 @@ pub async fn run_with_retry( ) -> Result where F: Fn() -> Ft, - Ft: Future> + Send, + Ft: std::future::Future> + Send, C: Fn(&E) -> ErrorClass, E: Into, { @@ -68,6 +68,49 @@ where } } +pub fn run_with_retry_sync( + what: &str, + max_attempts: usize, + backoff: Duration, + op: F, + classify_error: C, +) -> Result +where + F: Fn() -> Result, + C: Fn(&E) -> ErrorClass, + E: Into, +{ + assert!(max_attempts > 0); + + let mut attempt = 1; + loop { + let result = (op)(); + match result { + Ok(output) => return Ok(output), + Err(err) => { + match classify_error(&err) { + ErrorClass::NoRetry => { + return Err(RetryError::FailedUnretryable(err.into())); + } + ErrorClass::Retry => { + info!( + "{} failed on attempt {} with retryable error: {:?}. Will retry after {:?}", + what, attempt, err.into(), backoff + ); + } + } + } + } + + // If we made it this far, we're retrying or failing at max retries + if attempt == max_attempts { + return Err(RetryError::FailedMaxAttempts(max_attempts)); + } + attempt += 1; + std::thread::sleep(backoff); + } +} + #[cfg(test)] mod tests { use super::*; @@ -179,4 +222,95 @@ mod tests { } assert_eq!(2, attempt.load(Ordering::Relaxed)); } + + #[test] + fn fail_max_attempts_sync() { + let attempt = Arc::new(AtomicU8::new(1)); + let result = { + let attempt = attempt.clone(); + assert_send(run_with_retry_sync( + "test", + 3, + Duration::from_millis(0), + { + let attempt = attempt.clone(); + move || { + attempt.fetch_add(1, Ordering::Relaxed); + Result::<(), _>::Err(FakeError) + } + }, + |_err| ErrorClass::Retry, + )) + }; + + assert!(matches!(result, Err(RetryError::FailedMaxAttempts(3)))); + // `attempt` holds the number of the next attempt, so 4 instead of 3 in this case + assert_eq!(4, attempt.load(Ordering::Relaxed)); + } + + #[test] + fn fail_then_succeed_sync() { + let attempt = Arc::new(AtomicU8::new(1)); + let result = { + let attempt = attempt.clone(); + run_with_retry_sync( + "test", + 3, + Duration::from_millis(0), + { + let attempt = attempt.clone(); + move || { + if attempt.fetch_add(1, Ordering::Relaxed) == 1 { + Err(FakeError) + } else { + Ok(2) + } + } + }, + |_err| ErrorClass::Retry, + ) + }; + + assert!(matches!(result, Ok(2))); + // `attempt` holds the number of the next attempt, so 3 instead of 2 in this case + assert_eq!(3, attempt.load(Ordering::Relaxed)); + } + + #[test] + fn unretryable_error_sync() { + let attempt = Arc::new(AtomicU8::new(1)); + let result = { + let attempt = attempt.clone(); + run_with_retry_sync( + "test", + 3, + Duration::from_millis(0), + { + let attempt = attempt.clone(); + move || { + if attempt.fetch_add(1, Ordering::Relaxed) == 1 { + Err(UnretryableError) + } else { + Ok(2) + } + } + }, + |err| { + if matches!(err, UnretryableError) { + ErrorClass::NoRetry + } else { + ErrorClass::Retry + } + }, + ) + }; + + match result { + Err(RetryError::FailedUnretryable(err)) => { + assert!(err.downcast_ref::().is_some()); + } + _ => panic!("should be an unretryable error"), + } + assert_eq!(2, attempt.load(Ordering::Relaxed)); + } } diff --git a/tools/ci-build/smithy-rs-tool-common/src/shell.rs b/tools/ci-build/smithy-rs-tool-common/src/shell.rs index 9136ab541..d67604c20 100644 --- a/tools/ci-build/smithy-rs-tool-common/src/shell.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/shell.rs @@ -3,6 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +//! In general, the `crate::command` module should be preferred over this one going forward. +//! +//! This module was an attempt to make unit testing against command-line tools easier (especially +//! in regards to git), but over time we've been realizing it's easier to just set up fake git +//! repositories to run real commands against, or to mock out individual pieces of functionality +//! where needed rather than individual commands. This module requires a ton of boilerplate for +//! what is providing. + use anyhow::Result; use async_trait::async_trait; use std::process::Output; @@ -15,7 +23,7 @@ pub trait ShellOperation { fn run(&self) -> Result; /// Runs the command asynchronously. - #[cfg(feature = "async-shell")] + #[cfg(feature = "async")] async fn spawn(self) -> Result where Self: Sized + 'static, diff --git a/tools/ci-cdk/canary-runner/Cargo.lock b/tools/ci-cdk/canary-runner/Cargo.lock index 4af4fa079..6da3d4076 100644 --- a/tools/ci-cdk/canary-runner/Cargo.lock +++ b/tools/ci-cdk/canary-runner/Cargo.lock @@ -55,7 +55,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -66,7 +66,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1012,7 +1012,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1582,7 +1582,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1782,18 +1782,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2241,7 +2241,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2367,6 +2367,7 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "tokio", "toml", "tracing", @@ -2439,9 +2440,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -2508,22 +2509,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2607,7 +2608,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2679,7 +2680,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2863,7 +2864,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -2897,7 +2898,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/tools/ci-cdk/canary-runner/Cargo.toml b/tools/ci-cdk/canary-runner/Cargo.toml index b3e8cbf42..3235945fa 100644 --- a/tools/ci-cdk/canary-runner/Cargo.toml +++ b/tools/ci-cdk/canary-runner/Cargo.toml @@ -26,7 +26,7 @@ semver = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" sha1 = "0.10.1" -smithy-rs-tool-common = { version = "0.1", path = "../../ci-build/smithy-rs-tool-common", features = ["async-shell"] } +smithy-rs-tool-common = { version = "0.1", path = "../../ci-build/smithy-rs-tool-common", features = ["async"] } tokio = { version = "1.20.1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3.15", features = ["env-filter", "fmt"] } diff --git a/tools/ci-scripts/check-rust-runtimes b/tools/ci-scripts/check-rust-runtimes index abfcf5671..377f017ab 100755 --- a/tools/ci-scripts/check-rust-runtimes +++ b/tools/ci-scripts/check-rust-runtimes @@ -13,6 +13,9 @@ set -eux cd smithy-rs +echo -e "# ${C_YELLOW}Auditing runtime crate version numbers...${C_RESET}" +runtime-versioner audit --no-fetch + for runtime_path in \ "rust-runtime" \ "aws/rust-runtime" diff --git a/tools/ci-scripts/check-tools b/tools/ci-scripts/check-tools index afcbce908..fc7ced222 100755 --- a/tools/ci-scripts/check-tools +++ b/tools/ci-scripts/check-tools @@ -26,6 +26,7 @@ test_tool "tools/ci-build/changelogger" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/crate-hasher" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/difftags" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/publisher" "${RUST_STABLE_VERSION}" +test_tool "tools/ci-build/runtime-versioner" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/sdk-lints" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/sdk-versioner" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/smithy-rs-tool-common" "${RUST_STABLE_VERSION}"