-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tool to simulate a release dry run (#3327)
## Motivation and Context As we discovered in #3318, it's possible to cause unexpected breakage by releasing runtime crates. This tool automates setting up `aws-sdk-rust` (and manually, you can copy the patches into `~/.cargo/config.toml` for your entire system), to simulate the release of new runtime crates. <img width="1518" alt="Screenshot 2023-12-15 at 12 58 41 PM" src="https://github.com/smithy-lang/smithy-rs/assets/492903/59d6cb5c-d39c-4e42-98e2-6858d0884449"> ### Testing With this tool (and a small hack—I had to simulate releasing 1.1.100 so that the versions became the latest), I correctly caught the breaking changes from the previous release. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
- release-2025-03-04
- release-2025-02-20
- release-2025-02-12
- release-2025-02-03
- release-2025-01-28
- release-2025-01-23
- release-2025-01-17
- release-2025-01-14
- release-2024-12-30
- release-2024-12-26
- release-2024-12-16
- release-2024-12-03
- release-2024-11-05
- release-2024-10-30
- release-2024-10-24
- release-2024-10-09
- release-2024-10-05
- release-2024-10-04
- release-2024-10-03
- release-2024-09-26
- release-2024-09-17
- release-2024-09-09
- release-2024-08-28
- release-2024-08-16
- release-2024-08-14
- release-2024-08-08
- release-2024-07-16
- release-2024-07-09
- release-2024-07-03
- release-2024-06-19
- release-2024-06-17
- release-2024-06-12
- release-2024-06-10
- release-2024-06-03
- release-2024-05-28
- release-2024-05-22
- release-2024-05-21
- release-2024-05-08
- release-2024-04-30
- release-2024-04-19
- release-2024-04-11
- release-2024-04-02
- release-2024-03-25
- release-2024-03-12
- release-2024-02-22
- release-2024-02-15
- release-2024-02-08
- release-2024-01-24
- release-2024-01-18
- release-2024-01-10
Showing
3 changed files
with
546 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
name = "runtime-release-dryrun" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
clap = { version = "4", features = ["derive"] } | ||
anyhow = "1.0.75" | ||
indicatif = "0.17.7" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
// this tool is simple and works at what it does | ||
// potential improvements: | ||
// - support the release of rust-runtime crates | ||
// - support patching the users system-wide ~/.cargo/config.toml | ||
|
||
use std::path::{Path, PathBuf}; | ||
use std::process::Command; | ||
use std::time::Duration; | ||
|
||
use anyhow::{bail, Context, Result}; | ||
use clap::Parser; | ||
use indicatif::{ProgressBar, ProgressStyle}; | ||
|
||
#[derive(Parser, Debug)] | ||
struct DryRunSdk { | ||
/// Path to the aws-sdk-rust repo | ||
#[clap(long)] | ||
pub sdk_path: PathBuf, | ||
|
||
/// Tag of the aws-sdk-rust repo to dry-run against | ||
#[clap(long)] | ||
pub rust_sdk_tag: String, | ||
|
||
/// Path to the artifact produced by the release-dry run | ||
#[clap(long)] | ||
pub smithy_rs_release: PathBuf, | ||
} | ||
|
||
#[derive(Parser, Debug)] | ||
#[clap( | ||
name = "runtime-release-dryrun", | ||
about = "CLI tool to prepare the aws-sdk-rust to test the result of releasing a new set of runtime crates.", | ||
version | ||
)] | ||
#[allow(clippy::enum_variant_names)] // Want the "use" prefix in the CLI subcommand names for clarity | ||
enum Args { | ||
/// Dry run a smithy-rs release against a rust SDK release | ||
/// | ||
/// You will need: | ||
/// 1. An `aws-sdk-rust` repo with a clean working tree | ||
/// 2. A directory containing the artifacts from a smithy-rs release dry run. This is an artifact | ||
/// named `artifacts-generate-smithy-rs-release` from the GH action (e.g. https://github.com/smithy-lang/smithy-rs/actions/runs/7200898068) | ||
/// 3. An `aws-sdk-rust` release tag you want to test against | ||
/// | ||
/// After running the tool, you might want to do something like `cargo test` in `s3`. Make sure | ||
/// to run `cargo update` to pull in the new dependencies. Use `cargo tree` to confirm you're | ||
/// actually consuming the new versions. | ||
#[clap(verbatim_doc_comment)] | ||
DryRunSdk(DryRunSdk), | ||
} | ||
|
||
fn main() -> Result<()> { | ||
let args = Args::parse(); | ||
match args { | ||
Args::DryRunSdk(args) => dry_run_sdk(args).map_err(|err| { | ||
// workaround an indicatif (bug?) where one character is stripped from output on the error message | ||
eprintln!(" "); | ||
err | ||
})?, | ||
} | ||
Ok(()) | ||
} | ||
|
||
fn step<T>(message: &'static str, step: impl FnOnce() -> Result<T>) -> Result<T> { | ||
let spinner = ProgressBar::new_spinner() | ||
.with_message(message) | ||
.with_style(ProgressStyle::with_template("{spinner} {msg} {elapsed}").unwrap()); | ||
spinner.enable_steady_tick(Duration::from_millis(100)); | ||
let result = step(); | ||
let check = match &result { | ||
Ok(_) => "✅", | ||
Err(_) => "❌", | ||
}; | ||
spinner.set_style(ProgressStyle::with_template("{msg} {elapsed}").unwrap()); | ||
spinner.finish_with_message(format!("{check} {message}")); | ||
result | ||
} | ||
|
||
fn run(command: &mut Command) -> anyhow::Result<()> { | ||
let status = command.output()?; | ||
if !status.status.success() { | ||
bail!( | ||
"command `{:?}` failed:\n{}{}", | ||
command, | ||
String::from_utf8_lossy(&status.stdout), | ||
String::from_utf8_lossy(&status.stderr) | ||
); | ||
} | ||
Ok(()) | ||
} | ||
|
||
fn dry_run_sdk(args: DryRunSdk) -> Result<()> { | ||
step("Checking out SDK tag", || { | ||
run(Command::new("git") | ||
.arg("checkout") | ||
.arg(&args.rust_sdk_tag) | ||
.current_dir(&args.sdk_path)) | ||
.context("failed to checkout aws-sdk-rust revision")?; | ||
Ok(()) | ||
})?; | ||
|
||
// By default the SDK dependencies also include a path component. This prevents | ||
// patching from working | ||
step("Applying version-only dependencies", || { | ||
run(Command::new("sdk-versioner") | ||
.args([ | ||
"use-version-dependencies", | ||
"--versions-toml", | ||
"versions.toml", | ||
"sdk", | ||
]) | ||
.current_dir(&args.sdk_path))?; | ||
|
||
run(Command::new("git") | ||
.args(["checkout", "-B", "smithy-release-dryrun"]) | ||
.current_dir(&args.sdk_path))?; | ||
run(Command::new("git") | ||
.args([ | ||
"commit", | ||
"-am", | ||
"removing path dependencies to allow patching", | ||
]) | ||
.current_dir(&args.sdk_path))?; | ||
Ok(()) | ||
})?; | ||
|
||
let patches = step("computing patches", || { | ||
let path = Path::new(&args.smithy_rs_release).join("crates-to-publish"); | ||
let crates_to_patch = std::fs::read_dir(&path) | ||
.context(format!("could list crates in directory {:?}", path))? | ||
.map(|dir| dir.unwrap().file_name()) | ||
.map(|osstr| osstr.into_string().expect("invalid utf-8 directory")) | ||
.collect::<Vec<_>>(); | ||
|
||
let patch_sections = crates_to_patch | ||
.iter() | ||
.map(|crte| { | ||
let path = Path::new(&args.smithy_rs_release) | ||
.join("crates-to-publish") | ||
.join(crte); | ||
assert!( | ||
path.exists(), | ||
"tried to reference a crate that did not exist!" | ||
); | ||
format!( | ||
"{crte} = {{ path = '{}' }}", | ||
path.canonicalize().unwrap().to_str().unwrap() | ||
) | ||
}) | ||
.collect::<Vec<_>>() | ||
.join("\n"); | ||
Ok(format!("[patch.crates-io]\n{patch_sections}")) | ||
})?; | ||
|
||
// Note: in the future we could also automatically apply this to the system wide ~/.cargo/config.toml | ||
step("apply patches to workspace Cargo.toml", || { | ||
let workspace_cargo_toml = Path::new(&args.sdk_path).join("Cargo.toml"); | ||
if !workspace_cargo_toml.exists() { | ||
bail!( | ||
"Could not find the workspace Cargo.toml to patch {:?}", | ||
workspace_cargo_toml | ||
); | ||
} | ||
let current_contents = std::fs::read_to_string(&workspace_cargo_toml) | ||
.context("could not read workspace cargo.toml")?; | ||
std::fs::write( | ||
workspace_cargo_toml, | ||
format!("{current_contents}\n{patches}"), | ||
)?; | ||
run(Command::new("git") | ||
.args(["commit", "-am", "patching workspace Cargo.toml"]) | ||
.current_dir(&args.sdk_path))?; | ||
Ok(()) | ||
})?; | ||
println!("{:?} has been updated to build against patches. Use `cargo update` to recompute the dependencies.", &args.sdk_path); | ||
Ok(()) | ||
} |