mirror of https://github.com/smithy-lang/smithy-rs
Fix SDK canary by pinning SDK versions to smithy-rs versions (#1145)
* Move canary-runner tool from aws-sdk-rust * Commonize git shell operations * Centralize package categorization logic * Pin smithy-rs revisions to SDK versions for the canary * Incorporate feedback
This commit is contained in:
parent
4c7515f6a8
commit
11c61f65c6
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,28 @@
|
|||
[package]
|
||||
name = "canary-runner"
|
||||
version = "0.1.0"
|
||||
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
|
||||
description = "Tool used to run the canary tests in CI"
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
publish = false
|
||||
|
||||
[workspace]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
aws-config = "0.3"
|
||||
aws-sdk-cloudwatch = "0.3"
|
||||
aws-sdk-lambda = "0.3"
|
||||
aws-sdk-s3 = "0.3"
|
||||
base64 = "0.13"
|
||||
crates_io_api = "0.7"
|
||||
lazy_static = "1"
|
||||
semver = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
structopt = "0.3"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
|
||||
smithy-rs-tool-common = { version = "0.1", path = "../../smithy-rs-tool-common", features = ["async-shell"] }
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0.
|
||||
#
|
||||
# Run by CI to check the canary-lambda
|
||||
set -e
|
||||
cd "$(dirname $0)"
|
||||
|
||||
cargo test
|
||||
cargo clippy
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
use anyhow::Result;
|
||||
use crates_io_api::AsyncClient;
|
||||
use lazy_static::lazy_static;
|
||||
use serde::Serialize;
|
||||
use std::time::Duration;
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
pub struct GenerateMatrixOpt {
|
||||
#[structopt(short, long)]
|
||||
sdk_versions: u8,
|
||||
|
||||
#[structopt(short, long)]
|
||||
rust_versions: Vec<String>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref CRATES_IO_CLIENT: AsyncClient = AsyncClient::new(
|
||||
"AWS_RUST_SDK_PUBLISHER (aws-sdk-rust@amazon.com)",
|
||||
Duration::from_secs(1)
|
||||
)
|
||||
.expect("valid client");
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct Output {
|
||||
sdk_version: Vec<String>,
|
||||
rust_version: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn generate_matrix(opt: GenerateMatrixOpt) -> Result<()> {
|
||||
let crate_response = CRATES_IO_CLIENT.get_crate("aws-config").await?;
|
||||
let output = Output {
|
||||
// The versions from the Crates IO client come back in descending order by version number
|
||||
sdk_version: crate_response
|
||||
.versions
|
||||
.into_iter()
|
||||
.filter(|v| !v.yanked)
|
||||
.map(|v| v.num)
|
||||
.take(opt.sdk_versions as usize)
|
||||
.collect(),
|
||||
rust_version: opt.rust_versions,
|
||||
};
|
||||
println!("{}", serde_json::to_string(&output)?);
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
use structopt::StructOpt;
|
||||
use tracing_subscriber::{filter::EnvFilter, prelude::*};
|
||||
|
||||
mod generate_matrix;
|
||||
mod run;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(name = "canary-runner")]
|
||||
enum Opt {
|
||||
#[structopt(alias = "generate-matrix")]
|
||||
GenerateMatrix(generate_matrix::GenerateMatrixOpt),
|
||||
|
||||
#[structopt(alias = "run")]
|
||||
Run(run::RunOpt),
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let filter_layer = EnvFilter::try_from_default_env()
|
||||
.or_else(|_| EnvFilter::try_new("warn,canary_runner=info"))
|
||||
.unwrap();
|
||||
tracing_subscriber::registry()
|
||||
.with(filter_layer)
|
||||
.with(tracing_subscriber::fmt::layer().with_target(false))
|
||||
.init();
|
||||
|
||||
let opt = Opt::from_args();
|
||||
match opt {
|
||||
Opt::GenerateMatrix(subopt) => generate_matrix::generate_matrix(subopt).await,
|
||||
Opt::Run(subopt) => run::run(subopt).await,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
// This is the code used by CI to run the canary Lambda.
|
||||
//
|
||||
// If running this locally, you'll need to make a clone of awslabs/smithy-rs in
|
||||
// the aws-sdk-rust project root.
|
||||
//
|
||||
// Also consider using the `AWS_PROFILE` and `AWS_REGION` environment variables
|
||||
// when running this locally.
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use aws_sdk_cloudwatch as cloudwatch;
|
||||
use aws_sdk_lambda as lambda;
|
||||
use aws_sdk_s3 as s3;
|
||||
use cloudwatch::model::StandardUnit;
|
||||
use s3::ByteStream;
|
||||
use semver::Version;
|
||||
use smithy_rs_tool_common::git;
|
||||
use smithy_rs_tool_common::shell::ShellOperation;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{env, path::Path};
|
||||
use structopt::StructOpt;
|
||||
use tokio::process::Command;
|
||||
use tracing::{error, info};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
// Occasionally, a breaking change introduced in smithy-rs will cause the canary to fail
|
||||
// for older versions of the SDK since the canary is in the smithy-rs repository and will
|
||||
// get fixed for that breaking change. When this happens, the older SDK versions can be
|
||||
// pinned to a commit hash in the smithy-rs repository to get old canary code that still
|
||||
// compiles against that version of the SDK.
|
||||
static ref PINNED_SMITHY_RS_VERSIONS: Vec<(Version, &'static str)> = {
|
||||
let mut pinned = vec![
|
||||
// Versions <= 0.6.0 no longer compile against the canary after this commit in smithy-rs
|
||||
// due to the breaking change in https://github.com/awslabs/smithy-rs/pull/1085
|
||||
(Version::parse("0.6.0").unwrap(), "d48c234796a16d518ca9e1dda5c7a1da4904318c"),
|
||||
];
|
||||
pinned.sort();
|
||||
pinned
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
pub struct RunOpt {
|
||||
#[structopt(long, about = "Version of the SDK to compile the canary against")]
|
||||
sdk_version: String,
|
||||
|
||||
#[structopt(
|
||||
long,
|
||||
about = "The name of the S3 bucket to upload the canary binary bundle to"
|
||||
)]
|
||||
lambda_code_s3_bucket_name: String,
|
||||
|
||||
#[structopt(
|
||||
long,
|
||||
about = "The name of the S3 bucket for the canary Lambda to interact with"
|
||||
)]
|
||||
lambda_test_s3_bucket_name: String,
|
||||
|
||||
#[structopt(long, about = "The ARN of the role that the Lambda will execute as")]
|
||||
lambda_execution_role_arn: String,
|
||||
}
|
||||
|
||||
pub async fn run(opt: RunOpt) -> Result<()> {
|
||||
let start_time = SystemTime::now();
|
||||
let config = aws_config::load_from_env().await;
|
||||
let result = run_canary(opt, &config).await;
|
||||
|
||||
let mut metrics = vec![
|
||||
(
|
||||
"canary-success",
|
||||
if result.is_ok() { 1.0 } else { 0.0 },
|
||||
StandardUnit::Count,
|
||||
),
|
||||
(
|
||||
"canary-failure",
|
||||
if result.is_ok() { 0.0 } else { 1.0 },
|
||||
StandardUnit::Count,
|
||||
),
|
||||
(
|
||||
"canary-total-time",
|
||||
start_time.elapsed().expect("time in range").as_secs_f64(),
|
||||
StandardUnit::Seconds,
|
||||
),
|
||||
];
|
||||
if let Ok(invoke_time) = result {
|
||||
metrics.push((
|
||||
"canary-invoke-time",
|
||||
invoke_time.as_secs_f64(),
|
||||
StandardUnit::Seconds,
|
||||
));
|
||||
}
|
||||
|
||||
let cloudwatch_client = cloudwatch::Client::new(&config);
|
||||
let mut request_builder = cloudwatch_client
|
||||
.put_metric_data()
|
||||
.namespace("aws-sdk-rust-canary");
|
||||
for metric in metrics {
|
||||
request_builder = request_builder.metric_data(
|
||||
cloudwatch::model::MetricDatum::builder()
|
||||
.metric_name(metric.0)
|
||||
.value(metric.1)
|
||||
.timestamp(SystemTime::now().into())
|
||||
.unit(metric.2)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
info!("Emitting metrics...");
|
||||
request_builder
|
||||
.send()
|
||||
.await
|
||||
.context("failed to emit metrics")?;
|
||||
|
||||
result.map(|_| ())
|
||||
}
|
||||
|
||||
async fn run_canary(opt: RunOpt, config: &aws_config::Config) -> Result<Duration> {
|
||||
let repo_root = git_root().await?;
|
||||
env::set_current_dir(repo_root.join("smithy-rs/tools/ci-cdk/canary-lambda"))
|
||||
.context("failed to change working directory")?;
|
||||
|
||||
use_correct_revision(&opt).await?;
|
||||
|
||||
info!("Generating canary Cargo.toml...");
|
||||
generate_cargo_toml(&opt.sdk_version).await?;
|
||||
|
||||
info!("Building the canary...");
|
||||
let bundle_path = build_bundle(&opt.sdk_version).await?;
|
||||
let bundle_file_name = bundle_path.file_name().unwrap().to_str().unwrap();
|
||||
let bundle_name = bundle_path.file_stem().unwrap().to_str().unwrap();
|
||||
|
||||
let s3_client = s3::Client::new(config);
|
||||
let lambda_client = lambda::Client::new(config);
|
||||
|
||||
info!("Uploading Lambda code bundle to S3...");
|
||||
upload_bundle(
|
||||
s3_client,
|
||||
&opt.lambda_code_s3_bucket_name,
|
||||
bundle_file_name,
|
||||
&bundle_path,
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!(
|
||||
"Creating the canary Lambda function named {}...",
|
||||
bundle_name
|
||||
);
|
||||
create_lambda_fn(
|
||||
lambda_client.clone(),
|
||||
bundle_name,
|
||||
bundle_file_name,
|
||||
&opt.lambda_execution_role_arn,
|
||||
&opt.lambda_code_s3_bucket_name,
|
||||
&opt.lambda_test_s3_bucket_name,
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!("Invoking the canary Lambda...");
|
||||
let invoke_start_time = SystemTime::now();
|
||||
let invoke_result = invoke_lambda(lambda_client.clone(), bundle_name).await;
|
||||
let invoke_time = invoke_start_time.elapsed().expect("time in range");
|
||||
|
||||
info!("Deleting the canary Lambda...");
|
||||
delete_lambda_fn(lambda_client, bundle_name).await?;
|
||||
|
||||
invoke_result.map(|_| invoke_time)
|
||||
}
|
||||
|
||||
async fn use_correct_revision(opt: &RunOpt) -> Result<()> {
|
||||
let sdk_version = Version::parse(&opt.sdk_version).expect("valid version");
|
||||
if let Some((version, commit_hash)) = PINNED_SMITHY_RS_VERSIONS
|
||||
.iter()
|
||||
.find(|(v, _)| v >= &sdk_version)
|
||||
{
|
||||
info!(
|
||||
"SDK version {} requires smithy-rs@{} to successfully compile the canary",
|
||||
version, commit_hash
|
||||
);
|
||||
let smithy_rs_root = git::find_git_repository_root("smithy-rs", ".")?;
|
||||
git::CheckoutRevision::new(smithy_rs_root, *commit_hash)
|
||||
.spawn()
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn generate_cargo_toml(sdk_version: &str) -> Result<()> {
|
||||
let status = Command::new("./write-cargo-toml.py")
|
||||
.arg("--sdk-version")
|
||||
.arg(sdk_version)
|
||||
.status()
|
||||
.await?;
|
||||
if !status.success() {
|
||||
bail!("Failed to generate canary Cargo.toml");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the path to the compiled bundle zip file
|
||||
async fn build_bundle(sdk_version: &str) -> Result<PathBuf> {
|
||||
let output = Command::new("./build-bundle.sh")
|
||||
.arg(sdk_version)
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.output()
|
||||
.await?;
|
||||
if !output.status.success() {
|
||||
error!(
|
||||
"{}",
|
||||
std::str::from_utf8(&output.stderr).expect("valid utf-8")
|
||||
);
|
||||
bail!("Failed to build the canary bundle");
|
||||
} else {
|
||||
Ok(PathBuf::from(String::from_utf8(output.stdout)?.trim()))
|
||||
}
|
||||
}
|
||||
|
||||
async fn upload_bundle(
|
||||
s3_client: s3::Client,
|
||||
s3_bucket: &str,
|
||||
file_name: &str,
|
||||
bundle_path: &Path,
|
||||
) -> Result<()> {
|
||||
s3_client
|
||||
.put_object()
|
||||
.bucket(s3_bucket)
|
||||
.key(file_name)
|
||||
.body(
|
||||
ByteStream::from_path(bundle_path)
|
||||
.await
|
||||
.context("failed to load bundle file")?,
|
||||
)
|
||||
.send()
|
||||
.await
|
||||
.context("failed to upload bundle to S3")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_lambda_fn(
|
||||
lambda_client: lambda::Client,
|
||||
bundle_name: &str,
|
||||
bundle_file_name: &str,
|
||||
execution_role: &str,
|
||||
code_s3_bucket: &str,
|
||||
test_s3_bucket: &str,
|
||||
) -> Result<()> {
|
||||
use lambda::model::*;
|
||||
|
||||
lambda_client
|
||||
.create_function()
|
||||
.function_name(bundle_name)
|
||||
.runtime(Runtime::Providedal2)
|
||||
.role(execution_role)
|
||||
.handler("aws-sdk-rust-lambda-canary")
|
||||
.code(
|
||||
FunctionCode::builder()
|
||||
.s3_bucket(code_s3_bucket)
|
||||
.s3_key(bundle_file_name)
|
||||
.build(),
|
||||
)
|
||||
.publish(true)
|
||||
.environment(
|
||||
Environment::builder()
|
||||
.variables("RUST_BACKTRACE", "1")
|
||||
.variables("CANARY_S3_BUCKET_NAME", test_s3_bucket)
|
||||
.variables(
|
||||
"CANARY_EXPECTED_TRANSCRIBE_RESULT",
|
||||
"Good day to you transcribe. This is Polly talking to you from the Rust ST K.",
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
.timeout(60)
|
||||
.send()
|
||||
.await
|
||||
.context("failed to create canary Lambda function")?;
|
||||
|
||||
let mut attempts = 0;
|
||||
let mut state = State::Pending;
|
||||
while !matches!(state, State::Active) && attempts < 20 {
|
||||
info!("Waiting 1 second for Lambda to become active...");
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
let configuration = lambda_client
|
||||
.get_function_configuration()
|
||||
.function_name(bundle_name)
|
||||
.send()
|
||||
.await
|
||||
.context("failed to get Lambda function status")?;
|
||||
state = configuration.state.unwrap();
|
||||
attempts += 1;
|
||||
}
|
||||
if !matches!(state, State::Active) {
|
||||
bail!("Timed out waiting for canary Lambda to become active");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn invoke_lambda(lambda_client: lambda::Client, bundle_name: &str) -> Result<()> {
|
||||
use lambda::model::*;
|
||||
use lambda::Blob;
|
||||
|
||||
let response = lambda_client
|
||||
.invoke()
|
||||
.function_name(bundle_name)
|
||||
.invocation_type(InvocationType::RequestResponse)
|
||||
.log_type(LogType::Tail)
|
||||
.payload(Blob::new(&b"{}"[..]))
|
||||
.send()
|
||||
.await
|
||||
.context("failed to invoke the canary Lambda")?;
|
||||
|
||||
if let Some(log_result) = response.log_result {
|
||||
info!(
|
||||
"Last 4 KB of canary logs:\n----\n{}\n----\n",
|
||||
std::str::from_utf8(&base64::decode(&log_result)?)?
|
||||
);
|
||||
}
|
||||
if response.status_code != 200 {
|
||||
bail!(
|
||||
"Canary failed: {}",
|
||||
response
|
||||
.function_error
|
||||
.as_deref()
|
||||
.unwrap_or("<no error given>")
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_lambda_fn(lambda_client: lambda::Client, bundle_name: &str) -> Result<()> {
|
||||
lambda_client
|
||||
.delete_function()
|
||||
.function_name(bundle_name)
|
||||
.send()
|
||||
.await
|
||||
.context("failed to delete Lambda")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn git_root() -> Result<PathBuf> {
|
||||
let output = Command::new("git")
|
||||
.arg("rev-parse")
|
||||
.arg("--show-toplevel")
|
||||
.output()
|
||||
.await
|
||||
.context("couldn't find repository root")?;
|
||||
Ok(PathBuf::from(String::from_utf8(output.stdout)?.trim()))
|
||||
}
|
|
@ -952,6 +952,7 @@ dependencies = [
|
|||
"regex",
|
||||
"semver",
|
||||
"serde_json",
|
||||
"smithy-rs-tool-common",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"toml",
|
||||
|
@ -1226,6 +1227,15 @@ version = "1.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "smithy-rs-tool-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.2"
|
||||
|
|
|
@ -23,6 +23,7 @@ num_cpus = "1.13"
|
|||
regex = "1.5.4"
|
||||
semver = "1.0"
|
||||
serde_json = "1"
|
||||
smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common", features = ["async-shell"] }
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1.12", features = ["full"] }
|
||||
toml = { version = "0.5.8", features = ["preserve_order"] }
|
||||
|
|
|
@ -15,8 +15,8 @@ pub use get_owners::GetOwners;
|
|||
pub use publish::Publish;
|
||||
pub use yank::Yank;
|
||||
|
||||
use crate::shell::handle_failure;
|
||||
use anyhow::{Context, Result};
|
||||
use smithy_rs_tool_common::shell::handle_failure;
|
||||
use std::process::Command;
|
||||
|
||||
/// Confirms that cargo exists on the path.
|
||||
|
|
|
@ -3,39 +3,37 @@
|
|||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
use crate::shell::{handle_failure, ShellOperation};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use smithy_rs_tool_common::shell::{handle_failure, ShellOperation};
|
||||
use std::process::Command;
|
||||
|
||||
pub struct AddOwner<'a> {
|
||||
pub struct AddOwner {
|
||||
program: &'static str,
|
||||
package_name: &'a str,
|
||||
owner: &'a str,
|
||||
package_name: String,
|
||||
owner: String,
|
||||
}
|
||||
|
||||
impl<'a> AddOwner<'a> {
|
||||
pub fn new(package_name: &'a str, owner: &'a str) -> AddOwner<'a> {
|
||||
impl AddOwner {
|
||||
pub fn new(package_name: impl Into<String>, owner: impl Into<String>) -> AddOwner {
|
||||
AddOwner {
|
||||
program: "cargo",
|
||||
package_name,
|
||||
owner,
|
||||
package_name: package_name.into(),
|
||||
owner: owner.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<'a> ShellOperation for AddOwner<'a> {
|
||||
impl ShellOperation for AddOwner {
|
||||
type Output = ();
|
||||
|
||||
async fn spawn(&self) -> Result<()> {
|
||||
fn run(&self) -> Result<()> {
|
||||
let mut command = Command::new(self.program);
|
||||
command
|
||||
.arg("owner")
|
||||
.arg("--add")
|
||||
.arg(self.owner)
|
||||
.arg(self.package_name);
|
||||
let output = tokio::task::spawn_blocking(move || command.output()).await??;
|
||||
.arg(&self.owner)
|
||||
.arg(&self.package_name);
|
||||
let output = command.output()?;
|
||||
handle_failure("add owner", &output)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -44,13 +42,14 @@ impl<'a> ShellOperation for AddOwner<'a> {
|
|||
#[cfg(all(test, not(target_os = "windows")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use smithy_rs_tool_common::shell::ShellOperation;
|
||||
|
||||
#[tokio::test]
|
||||
async fn add_owner_success() {
|
||||
AddOwner {
|
||||
program: "./fake_cargo/cargo_success",
|
||||
package_name: "aws-sdk-s3",
|
||||
owner: "github:awslabs:rust-sdk-owners",
|
||||
package_name: "aws-sdk-s3".into(),
|
||||
owner: "github:awslabs:rust-sdk-owners".into(),
|
||||
}
|
||||
.spawn()
|
||||
.await
|
||||
|
@ -61,8 +60,8 @@ mod tests {
|
|||
async fn get_owners_failed() {
|
||||
let result = AddOwner {
|
||||
program: "./fake_cargo/cargo_fails",
|
||||
package_name: "aws-sdk-s3",
|
||||
owner: "github:awslabs:rust-sdk-owners",
|
||||
package_name: "aws-sdk-s3".into(),
|
||||
owner: "github:awslabs:rust-sdk-owners".into(),
|
||||
}
|
||||
.spawn()
|
||||
.await;
|
||||
|
|
|
@ -3,34 +3,32 @@
|
|||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
use crate::shell::{handle_failure, output_text, ShellOperation};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use regex::Regex;
|
||||
use smithy_rs_tool_common::shell::{handle_failure, output_text, ShellOperation};
|
||||
use std::process::Command;
|
||||
|
||||
pub struct GetOwners<'a> {
|
||||
pub struct GetOwners {
|
||||
program: &'static str,
|
||||
package_name: &'a str,
|
||||
package_name: String,
|
||||
}
|
||||
|
||||
impl<'a> GetOwners<'a> {
|
||||
pub fn new(package_name: &'a str) -> GetOwners<'a> {
|
||||
impl GetOwners {
|
||||
pub fn new(package_name: impl Into<String>) -> GetOwners {
|
||||
GetOwners {
|
||||
program: "cargo",
|
||||
package_name,
|
||||
package_name: package_name.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<'a> ShellOperation for GetOwners<'a> {
|
||||
impl ShellOperation for GetOwners {
|
||||
type Output = Vec<String>;
|
||||
|
||||
async fn spawn(&self) -> Result<Vec<String>> {
|
||||
fn run(&self) -> Result<Vec<String>> {
|
||||
let mut command = Command::new(self.program);
|
||||
command.arg("owner").arg("--list").arg(self.package_name);
|
||||
let output = tokio::task::spawn_blocking(move || command.output()).await??;
|
||||
command.arg("owner").arg("--list").arg(&self.package_name);
|
||||
let output = command.output()?;
|
||||
handle_failure("get crate owners", &output)?;
|
||||
|
||||
let mut result = Vec::new();
|
||||
|
@ -59,7 +57,7 @@ mod tests {
|
|||
async fn get_owners_success() {
|
||||
let owners = GetOwners {
|
||||
program: "./fake_cargo/cargo_owner_list",
|
||||
package_name: "aws-sdk-s3",
|
||||
package_name: "aws-sdk-s3".into(),
|
||||
}
|
||||
.spawn()
|
||||
.await
|
||||
|
@ -77,7 +75,7 @@ mod tests {
|
|||
async fn get_owners_failed() {
|
||||
let result = GetOwners {
|
||||
program: "./fake_cargo/cargo_fails",
|
||||
package_name: "aws-sdk-s3",
|
||||
package_name: "aws-sdk-s3".into(),
|
||||
}
|
||||
.spawn()
|
||||
.await;
|
||||
|
|
|
@ -4,42 +4,40 @@
|
|||
*/
|
||||
|
||||
use crate::package::PackageHandle;
|
||||
use crate::shell::{capture_error, output_text, ShellOperation};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use std::path::Path;
|
||||
use smithy_rs_tool_common::shell::{capture_error, output_text, ShellOperation};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use tracing::info;
|
||||
|
||||
pub struct Publish<'a> {
|
||||
pub struct Publish {
|
||||
program: &'static str,
|
||||
package_handle: &'a PackageHandle,
|
||||
package_path: &'a Path,
|
||||
package_handle: PackageHandle,
|
||||
package_path: PathBuf,
|
||||
}
|
||||
|
||||
impl<'a> Publish<'a> {
|
||||
pub fn new(package_handle: &'a PackageHandle, package_path: &'a Path) -> Publish<'a> {
|
||||
impl Publish {
|
||||
pub fn new(package_handle: PackageHandle, package_path: impl Into<PathBuf>) -> Publish {
|
||||
Publish {
|
||||
program: "cargo",
|
||||
package_handle,
|
||||
package_path,
|
||||
package_path: package_path.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<'a> ShellOperation for Publish<'a> {
|
||||
impl ShellOperation for Publish {
|
||||
type Output = ();
|
||||
|
||||
async fn spawn(&self) -> Result<()> {
|
||||
fn run(&self) -> Result<()> {
|
||||
let mut command = Command::new(self.program);
|
||||
command
|
||||
.current_dir(self.package_path)
|
||||
.current_dir(&self.package_path)
|
||||
.env("CARGO_INCREMENTAL", "0") // Disable incremental compilation to reduce disk space used
|
||||
.arg("publish")
|
||||
.arg("--jobs")
|
||||
.arg("1");
|
||||
let output = tokio::task::spawn_blocking(move || command.output()).await??;
|
||||
let output = command.output()?;
|
||||
if !output.status.success() {
|
||||
let (stdout, stderr) = output_text(&output);
|
||||
let already_uploaded_msg = format!(
|
||||
|
@ -69,11 +67,11 @@ mod tests {
|
|||
async fn publish_succeeds() {
|
||||
Publish {
|
||||
program: "./fake_cargo/cargo_success",
|
||||
package_handle: &PackageHandle::new(
|
||||
package_handle: PackageHandle::new(
|
||||
"aws-sdk-dynamodb",
|
||||
Version::parse("0.0.22-alpha").unwrap(),
|
||||
),
|
||||
package_path: &env::current_dir().unwrap(),
|
||||
package_path: env::current_dir().unwrap().into(),
|
||||
}
|
||||
.spawn()
|
||||
.await
|
||||
|
@ -84,11 +82,11 @@ mod tests {
|
|||
async fn publish_fails() {
|
||||
let result = Publish {
|
||||
program: "./fake_cargo/cargo_fails",
|
||||
package_handle: &PackageHandle::new(
|
||||
package_handle: PackageHandle::new(
|
||||
"something",
|
||||
Version::parse("0.0.22-alpha").unwrap(),
|
||||
),
|
||||
package_path: &env::current_dir().unwrap(),
|
||||
package_path: env::current_dir().unwrap().into(),
|
||||
}
|
||||
.spawn()
|
||||
.await;
|
||||
|
@ -106,11 +104,11 @@ mod tests {
|
|||
async fn publish_fails_already_uploaded() {
|
||||
Publish {
|
||||
program: "./fake_cargo/cargo_publish_already_published",
|
||||
package_handle: &PackageHandle::new(
|
||||
package_handle: PackageHandle::new(
|
||||
"aws-sdk-dynamodb",
|
||||
Version::parse("0.0.22-alpha").unwrap(),
|
||||
),
|
||||
package_path: &env::current_dir().unwrap(),
|
||||
package_path: env::current_dir().unwrap().into(),
|
||||
}
|
||||
.spawn()
|
||||
.await
|
||||
|
|
|
@ -4,43 +4,41 @@
|
|||
*/
|
||||
|
||||
use crate::package::PackageHandle;
|
||||
use crate::shell::{capture_error, output_text, ShellOperation};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use std::path::Path;
|
||||
use smithy_rs_tool_common::shell::{capture_error, output_text, ShellOperation};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use tracing::info;
|
||||
|
||||
/// Yanks a package version from crates.io
|
||||
pub struct Yank<'a> {
|
||||
pub struct Yank {
|
||||
program: &'static str,
|
||||
package_handle: &'a PackageHandle,
|
||||
package_path: &'a Path,
|
||||
package_handle: PackageHandle,
|
||||
package_path: PathBuf,
|
||||
}
|
||||
|
||||
impl<'a> Yank<'a> {
|
||||
pub fn new(package_handle: &'a PackageHandle, package_path: &'a Path) -> Yank<'a> {
|
||||
impl Yank {
|
||||
pub fn new(package_handle: PackageHandle, package_path: impl Into<PathBuf>) -> Yank {
|
||||
Yank {
|
||||
program: "cargo",
|
||||
package_handle,
|
||||
package_path,
|
||||
package_path: package_path.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<'a> ShellOperation for Yank<'a> {
|
||||
impl ShellOperation for Yank {
|
||||
type Output = ();
|
||||
|
||||
async fn spawn(&self) -> Result<()> {
|
||||
fn run(&self) -> Result<()> {
|
||||
let mut command = Command::new(self.program);
|
||||
command
|
||||
.current_dir(self.package_path)
|
||||
.current_dir(&self.package_path)
|
||||
.arg("yank")
|
||||
.arg("--vers")
|
||||
.arg(format!("{}", self.package_handle.version))
|
||||
.arg(&self.package_handle.name);
|
||||
let output = tokio::task::spawn_blocking(move || command.output()).await??;
|
||||
let output = command.output()?;
|
||||
if !output.status.success() {
|
||||
let (_, stderr) = output_text(&output);
|
||||
let no_such_version = format!(
|
||||
|
@ -70,11 +68,11 @@ mod tests {
|
|||
async fn yank_succeeds() {
|
||||
Yank {
|
||||
program: "./fake_cargo/cargo_success",
|
||||
package_handle: &PackageHandle::new(
|
||||
package_handle: PackageHandle::new(
|
||||
"aws-sdk-dynamodb",
|
||||
Version::parse("0.0.22-alpha").unwrap(),
|
||||
),
|
||||
package_path: &env::current_dir().unwrap(),
|
||||
package_path: env::current_dir().unwrap().into(),
|
||||
}
|
||||
.spawn()
|
||||
.await
|
||||
|
@ -85,11 +83,11 @@ mod tests {
|
|||
async fn yank_fails() {
|
||||
let result = Yank {
|
||||
program: "./fake_cargo/cargo_fails",
|
||||
package_handle: &PackageHandle::new(
|
||||
package_handle: PackageHandle::new(
|
||||
"something",
|
||||
Version::parse("0.0.22-alpha").unwrap(),
|
||||
),
|
||||
package_path: &env::current_dir().unwrap(),
|
||||
package_path: env::current_dir().unwrap().into(),
|
||||
}
|
||||
.spawn()
|
||||
.await;
|
||||
|
@ -107,8 +105,8 @@ mod tests {
|
|||
async fn yank_no_such_version() {
|
||||
Yank {
|
||||
program: "./fake_cargo/cargo_yank_not_found",
|
||||
package_handle: &PackageHandle::new("aws-sigv4", Version::parse("0.0.0").unwrap()),
|
||||
package_path: &env::current_dir().unwrap(),
|
||||
package_handle: PackageHandle::new("aws-sigv4", Version::parse("0.0.0").unwrap()),
|
||||
package_path: env::current_dir().unwrap().into(),
|
||||
}
|
||||
.spawn()
|
||||
.await
|
||||
|
|
|
@ -14,10 +14,8 @@ use subcommand::hydrate_readme::subcommand_hydrate_readme;
|
|||
|
||||
mod cargo;
|
||||
mod fs;
|
||||
mod git;
|
||||
mod package;
|
||||
mod repo;
|
||||
mod shell;
|
||||
mod sort;
|
||||
mod subcommand;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::sort::dependency_order;
|
|||
use anyhow::{Context, Result};
|
||||
use cargo_toml::{Dependency, DepsSet, Manifest};
|
||||
use semver::Version;
|
||||
use smithy_rs_tool_common::package::PackageCategory;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
|
@ -17,34 +18,6 @@ use std::path::{Path, PathBuf};
|
|||
use tokio::fs;
|
||||
use tracing::warn;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum PackageCategory {
|
||||
SmithyRuntime,
|
||||
AwsRuntime,
|
||||
AwsSdk,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl PackageCategory {
|
||||
/// Returns true if the category is `AwsRuntime` or `AwsSdk`
|
||||
pub fn is_sdk(&self) -> bool {
|
||||
matches!(self, PackageCategory::AwsRuntime | PackageCategory::AwsSdk)
|
||||
}
|
||||
|
||||
/// Categorizes a package based on its name
|
||||
pub fn from_package_name(name: &str) -> PackageCategory {
|
||||
if name.starts_with("aws-smithy-") {
|
||||
PackageCategory::SmithyRuntime
|
||||
} else if name.starts_with("aws-sdk-") {
|
||||
PackageCategory::AwsSdk
|
||||
} else if name.starts_with("aws-") {
|
||||
PackageCategory::AwsRuntime
|
||||
} else {
|
||||
PackageCategory::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Information required to identify a package (crate).
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub struct PackageHandle {
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
//! Local filesystem git repository discovery. This enables the tool to
|
||||
//! orient itself despite being run anywhere from within the git repo.
|
||||
|
||||
use crate::git;
|
||||
use crate::shell::ShellOperation;
|
||||
use crate::{SDK_REPO_CRATE_PATH, SDK_REPO_NAME};
|
||||
use anyhow::Result;
|
||||
use std::ffi::OsStr;
|
||||
use smithy_rs_tool_common::git;
|
||||
use smithy_rs_tool_common::shell::ShellOperation;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Git repository containing crates to be published.
|
||||
|
@ -20,51 +19,24 @@ pub struct Repository {
|
|||
}
|
||||
|
||||
impl Repository {
|
||||
pub fn new(repo_name: &str, path: impl Into<PathBuf>) -> Result<Repository> {
|
||||
let root = git::find_git_repository_root(repo_name, path.into())?;
|
||||
Ok(Repository { root })
|
||||
}
|
||||
|
||||
/// Returns the current tag of this repository
|
||||
pub async fn current_tag(&self) -> Result<String> {
|
||||
git::GetCurrentTag::new(&self.root).spawn().await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("failed to find {0} repository root")]
|
||||
RepositoryRootNotFound(String),
|
||||
}
|
||||
|
||||
/// Given a `location`, this function looks for the `aws-sdk-rust` git repository. If found,
|
||||
/// it resolves the `sdk/` directory. Otherwise, it returns the original `location`.
|
||||
pub async fn resolve_publish_location(location: &Path) -> PathBuf {
|
||||
match find_git_repository_root(SDK_REPO_NAME, location).await {
|
||||
pub fn resolve_publish_location(location: &Path) -> PathBuf {
|
||||
match Repository::new(SDK_REPO_NAME, location) {
|
||||
// If the given path was the `aws-sdk-rust` repo root, then resolve the `sdk/` directory to publish from
|
||||
Ok(sdk_repo) => sdk_repo.root.join(SDK_REPO_CRATE_PATH),
|
||||
// Otherwise, publish from the given path (likely the smithy-rs runtime bundle)
|
||||
Err(_) => location.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to find git repository root from the given location.
|
||||
pub async fn find_git_repository_root(
|
||||
repo_name: &str,
|
||||
location: impl Into<PathBuf>,
|
||||
) -> Result<Repository> {
|
||||
let mut current_dir = location.into();
|
||||
let os_name = OsStr::new(repo_name);
|
||||
loop {
|
||||
if is_git_root(¤t_dir) {
|
||||
if let Some(file_name) = current_dir.file_name() {
|
||||
if os_name == file_name {
|
||||
return Ok(Repository { root: current_dir });
|
||||
}
|
||||
}
|
||||
return Err(Error::RepositoryRootNotFound(repo_name.into()).into());
|
||||
} else if !current_dir.pop() {
|
||||
return Err(Error::RepositoryRootNotFound(repo_name.into()).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_git_root(path: &Path) -> bool {
|
||||
let path = path.join(".git");
|
||||
path.exists() && path.is_dir()
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ use crate::package::{discover_package_manifests, parse_version};
|
|||
use crate::SDK_REPO_NAME;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use semver::Version;
|
||||
use smithy_rs_tool_common::github_actions::running_in_github_actions;
|
||||
use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use toml::value::Table;
|
||||
|
@ -159,7 +159,7 @@ fn conditionally_disallow_publish(
|
|||
manifest_path: &Path,
|
||||
metadata: &mut toml::Value,
|
||||
) -> Result<bool> {
|
||||
let is_github_actions = env::var("GITHUB_ACTIONS").unwrap_or_default() == "true";
|
||||
let is_github_actions = running_in_github_actions();
|
||||
let is_example = is_example_manifest(manifest_path);
|
||||
|
||||
// Safe-guard to prevent accidental publish to crates.io. Add some friction
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
*/
|
||||
|
||||
use crate::fs::Fs;
|
||||
use crate::package::{discover_and_validate_package_batches, PackageCategory};
|
||||
use crate::package::discover_and_validate_package_batches;
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use semver::Version;
|
||||
use smithy_rs_tool_common::package::PackageCategory;
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
use tracing::info;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
use crate::repo::find_git_repository_root;
|
||||
use crate::repo::Repository;
|
||||
use crate::SMITHYRS_REPO_NAME;
|
||||
use anyhow::{Context, Result};
|
||||
use handlebars::Handlebars;
|
||||
|
@ -18,7 +18,7 @@ pub async fn subcommand_hydrate_readme(
|
|||
output: &Path,
|
||||
) -> Result<()> {
|
||||
let cwd = std::env::current_dir()?;
|
||||
let repository = find_git_repository_root(SMITHYRS_REPO_NAME, &cwd).await?;
|
||||
let repository = Repository::new(SMITHYRS_REPO_NAME, &cwd)?;
|
||||
let template_path = repository.root.join("aws/SDK_README.md.hb");
|
||||
let template_contents = fs::read(&template_path)
|
||||
.with_context(|| format!("Failed to read README template file at {:?}", template_path))?;
|
||||
|
|
|
@ -7,14 +7,14 @@ use crate::fs::Fs;
|
|||
use crate::package::{
|
||||
discover_and_validate_package_batches, Package, PackageBatch, PackageHandle, PackageStats,
|
||||
};
|
||||
use crate::repo::{find_git_repository_root, resolve_publish_location};
|
||||
use crate::shell::ShellOperation;
|
||||
use crate::repo::{resolve_publish_location, Repository};
|
||||
use crate::CRATE_OWNER;
|
||||
use crate::{cargo, SDK_REPO_NAME};
|
||||
use anyhow::{bail, Result};
|
||||
use crates_io_api::{AsyncClient, Error};
|
||||
use dialoguer::Confirm;
|
||||
use lazy_static::lazy_static;
|
||||
use smithy_rs_tool_common::shell::ShellOperation;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
@ -33,7 +33,7 @@ pub async fn subcommand_publish(location: &Path) -> Result<()> {
|
|||
// Make sure cargo exists
|
||||
cargo::confirm_installed_on_path()?;
|
||||
|
||||
let location = resolve_publish_location(location).await;
|
||||
let location = resolve_publish_location(location);
|
||||
|
||||
info!("Discovering crates to publish...");
|
||||
let (batches, stats) = discover_and_validate_package_batches(Fs::Real, &location).await?;
|
||||
|
@ -60,7 +60,7 @@ pub async fn subcommand_publish(location: &Path) -> Result<()> {
|
|||
// Only publish if it hasn't been published yet.
|
||||
if !is_published(&package.handle).await? {
|
||||
info!("Publishing `{}`...", package.handle);
|
||||
cargo::Publish::new(&package.handle, &package.crate_path)
|
||||
cargo::Publish::new(package.handle.clone(), &package.crate_path)
|
||||
.spawn()
|
||||
.await?;
|
||||
// Sometimes it takes a little bit of time for the new package version
|
||||
|
@ -94,7 +94,7 @@ async fn confirm_correct_tag(batches: &[Vec<Package>], location: &Path) -> Resul
|
|||
.next();
|
||||
if let Some(aws_config_version) = aws_config_version {
|
||||
let expected_tag = format!("v{}", aws_config_version);
|
||||
let repository = find_git_repository_root(SDK_REPO_NAME, location).await?;
|
||||
let repository = Repository::new(SDK_REPO_NAME, location)?;
|
||||
let current_tag = repository.current_tag().await?;
|
||||
if expected_tag != current_tag {
|
||||
bail!(
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
|
||||
use crate::cargo;
|
||||
use crate::fs::Fs;
|
||||
use crate::package::{
|
||||
discover_and_validate_package_batches, Package, PackageCategory, PackageHandle, Publish,
|
||||
};
|
||||
use crate::package::{discover_and_validate_package_batches, Package, PackageHandle, Publish};
|
||||
use crate::repo::resolve_publish_location;
|
||||
use crate::shell::ShellOperation;
|
||||
use anyhow::{bail, Result};
|
||||
use dialoguer::Confirm;
|
||||
use semver::Version;
|
||||
use smithy_rs_tool_common::package::PackageCategory;
|
||||
use smithy_rs_tool_common::shell::ShellOperation;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Semaphore;
|
||||
|
@ -40,7 +39,7 @@ pub async fn subcommand_yank_category(
|
|||
// Make sure cargo exists
|
||||
cargo::confirm_installed_on_path()?;
|
||||
|
||||
let location = resolve_publish_location(location).await;
|
||||
let location = resolve_publish_location(location);
|
||||
|
||||
info!("Discovering crates to yank...");
|
||||
let (batches, _) = discover_and_validate_package_batches(Fs::Real, &location).await?;
|
||||
|
@ -81,7 +80,7 @@ pub async fn subcommand_yank_category(
|
|||
let permit = semaphore.clone().acquire_owned().await.unwrap();
|
||||
tasks.push(tokio::spawn(async move {
|
||||
info!("Yanking `{}`...", package.handle);
|
||||
let result = cargo::Yank::new(&package.handle, &package.crate_path)
|
||||
let result = cargo::Yank::new(package.handle.clone(), &package.crate_path)
|
||||
.spawn()
|
||||
.await;
|
||||
drop(permit);
|
||||
|
|
|
@ -17,6 +17,17 @@ version = "1.0.52"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
@ -228,6 +239,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"pretty_assertions",
|
||||
"smithy-rs-tool-common",
|
||||
"structopt",
|
||||
"tempfile",
|
||||
"toml",
|
||||
|
@ -239,6 +251,14 @@ version = "1.0.133"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
|
||||
|
||||
[[package]]
|
||||
name = "smithy-rs-tool-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
|
|
|
@ -12,6 +12,7 @@ publish = false
|
|||
anyhow = "1.0"
|
||||
structopt = "0.3"
|
||||
toml = { version = "0.5.8", features = ["preserve_order"] }
|
||||
smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common" }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
use anyhow::bail;
|
||||
use smithy_rs_tool_common::package::{PackageCategory, SDK_PREFIX};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -11,18 +12,6 @@ use std::time::Instant;
|
|||
use structopt::StructOpt;
|
||||
use toml::value::{Table, Value};
|
||||
|
||||
const AWS_CONFIG: &str = "aws-config";
|
||||
const AWS_RUNTIME_CRATES: &[&str] = &[
|
||||
"aws-endpoint",
|
||||
"aws-http",
|
||||
"aws-hyper",
|
||||
"aws-sig-auth",
|
||||
"aws-sigv4",
|
||||
"aws-types",
|
||||
];
|
||||
const SDK_PREFIX: &str = "aws-sdk-";
|
||||
const SMITHY_PREFIX: &str = "aws-smithy-";
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(
|
||||
name = "sdk-versioner",
|
||||
|
@ -105,7 +94,8 @@ fn update_manifest(manifest_path: &Path, opt: &Opt) -> anyhow::Result<()> {
|
|||
fn update_dependencies(dependencies: &mut Table, opt: &Opt) -> anyhow::Result<bool> {
|
||||
let mut changed = false;
|
||||
for (key, value) in dependencies.iter_mut() {
|
||||
if is_sdk_or_runtime_crate(key) {
|
||||
let category = PackageCategory::from_package_name(key);
|
||||
if !matches!(category, PackageCategory::Unknown) {
|
||||
if !value.is_table() {
|
||||
*value = Value::Table(Table::new());
|
||||
}
|
||||
|
@ -116,20 +106,11 @@ fn update_dependencies(dependencies: &mut Table, opt: &Opt) -> anyhow::Result<bo
|
|||
Ok(changed)
|
||||
}
|
||||
|
||||
fn is_sdk_crate(name: &str) -> bool {
|
||||
is_service_crate(name) || name == AWS_CONFIG || AWS_RUNTIME_CRATES.iter().any(|&k| k == name)
|
||||
}
|
||||
|
||||
fn is_sdk_or_runtime_crate(name: &str) -> bool {
|
||||
is_sdk_crate(name) || name.starts_with(SMITHY_PREFIX)
|
||||
}
|
||||
|
||||
fn is_service_crate(name: &str) -> bool {
|
||||
name.starts_with(SDK_PREFIX)
|
||||
}
|
||||
|
||||
fn crate_path_name(name: &str) -> &str {
|
||||
if is_service_crate(name) {
|
||||
if matches!(
|
||||
PackageCategory::from_package_name(name),
|
||||
PackageCategory::AwsSdk
|
||||
) {
|
||||
&name[SDK_PREFIX.len()..]
|
||||
} else {
|
||||
name
|
||||
|
@ -137,7 +118,10 @@ fn crate_path_name(name: &str) -> &str {
|
|||
}
|
||||
|
||||
fn update_dependency_value(crate_name: &str, value: &mut Table, opt: &Opt) {
|
||||
let is_sdk_crate = is_sdk_crate(crate_name);
|
||||
let is_sdk_crate = matches!(
|
||||
PackageCategory::from_package_name(crate_name),
|
||||
PackageCategory::AwsSdk | PackageCategory::AwsRuntime,
|
||||
);
|
||||
|
||||
// Remove keys that will be replaced
|
||||
value.remove("version");
|
||||
|
|
|
@ -17,6 +17,17 @@ version = "1.0.51"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
|
@ -361,10 +372,19 @@ dependencies = [
|
|||
"git2",
|
||||
"gitignore",
|
||||
"pretty_assertions",
|
||||
"smithy-rs-tool-common",
|
||||
"structopt",
|
||||
"tempdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithy-rs-tool-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.25"
|
||||
|
|
|
@ -14,6 +14,7 @@ authors = ["Zelda Hessler <zhessler@amazon.com>"]
|
|||
anyhow = "1"
|
||||
git2 = "0.13"
|
||||
gitignore = "1"
|
||||
smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common" }
|
||||
structopt = { version = "0.3", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
mod fs;
|
||||
|
||||
use crate::fs::{delete_all_generated_files_and_folders, find_handwritten_files_and_folders};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use git2::{Commit, Oid, Repository, ResetType};
|
||||
use smithy_rs_tool_common::git::GetLastCommit;
|
||||
use smithy_rs_tool_common::shell::ShellOperation;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
@ -399,7 +401,7 @@ fn create_mirror_commit(aws_sdk_path: &Path, based_on_commit: &Commit) -> Result
|
|||
aws_sdk_path,
|
||||
)
|
||||
.context(here!())?;
|
||||
let commit_hash = find_last_commit(aws_sdk_path).context(here!())?;
|
||||
let commit_hash = GetLastCommit::new(aws_sdk_path).run().context(here!())?;
|
||||
|
||||
eprintln!("\tsuccessfully created mirror commit {}", commit_hash);
|
||||
|
||||
|
@ -462,19 +464,6 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn find_last_commit(repo_path: &Path) -> Result<String> {
|
||||
let output = Command::new("git")
|
||||
.arg("rev-parse")
|
||||
.arg("HEAD")
|
||||
.current_dir(&repo_path)
|
||||
.output()
|
||||
.map_err(|err| anyhow!("couldn't get commit hash: {}", err))?;
|
||||
|
||||
let hash = String::from_utf8_lossy(&output.stdout);
|
||||
|
||||
Ok(hash.to_string())
|
||||
}
|
||||
|
||||
/// For a slice containing `S` where `S: AsRef<OsStr>`, join all `S` into a space-separated String.
|
||||
fn stringify_args<S>(args: &[S]) -> String
|
||||
where
|
||||
|
@ -484,10 +473,6 @@ where
|
|||
args.join(" ")
|
||||
}
|
||||
|
||||
fn _is_running_in_github_action() -> bool {
|
||||
std::env::var("GITHUB_ACTIONS").unwrap_or_default() == "true"
|
||||
}
|
||||
|
||||
fn is_a_git_repository(dir: &Path) -> bool {
|
||||
dir.join(".git").is_dir()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithy-rs-tool-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "smithy-rs-tool-common"
|
||||
version = "0.1.0"
|
||||
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
publish = false
|
||||
|
||||
[workspace]
|
||||
|
||||
[features]
|
||||
async-shell = ["tokio"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
async-trait = "0.1"
|
||||
tokio = { version = "1", features = ["rt", "macros"], optional = true }
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0.
|
||||
#
|
||||
# Run by CI to check the canary-lambda
|
||||
set -e
|
||||
cd "$(dirname $0)"
|
||||
|
||||
cargo test
|
||||
cargo test --all-features
|
||||
cargo clippy
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
if [[ "$1" != "checkout" || "$2" != "test-revision" ]]; then
|
||||
echo "wrong arguments" >&2
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
if [[ "$1" != "rev-parse" || "$2" != "HEAD" ]]; then
|
||||
echo "wrong arguments" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "commithash"
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
mod checkout_revision;
|
||||
pub use checkout_revision::CheckoutRevision;
|
||||
|
||||
mod get_current_tag;
|
||||
pub use get_current_tag::GetCurrentTag;
|
||||
|
||||
mod get_last_commit;
|
||||
pub use get_last_commit::GetLastCommit;
|
||||
|
||||
/// Attempts to find git repository root from the given location.
|
||||
pub fn find_git_repository_root(repo_name: &str, location: impl AsRef<Path>) -> Result<PathBuf> {
|
||||
let mut current_dir = location.as_ref().canonicalize()?.to_path_buf();
|
||||
let os_name = OsStr::new(repo_name);
|
||||
loop {
|
||||
if is_git_root(¤t_dir) {
|
||||
if let Some(file_name) = current_dir.file_name() {
|
||||
if os_name == file_name {
|
||||
return Ok(current_dir);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if !current_dir.pop() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
bail!("failed to find {0} repository root", repo_name)
|
||||
}
|
||||
|
||||
fn is_git_root(path: &Path) -> bool {
|
||||
let path = path.join(".git");
|
||||
path.exists() && path.is_dir()
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
use crate::shell::{handle_failure, ShellOperation};
|
||||
use anyhow::Result;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
pub struct CheckoutRevision {
|
||||
program: &'static str,
|
||||
path: PathBuf,
|
||||
revision: String,
|
||||
}
|
||||
|
||||
impl CheckoutRevision {
|
||||
pub fn new(path: impl Into<PathBuf>, revision: impl Into<String>) -> Self {
|
||||
CheckoutRevision {
|
||||
program: "git",
|
||||
path: path.into(),
|
||||
revision: revision.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShellOperation for CheckoutRevision {
|
||||
type Output = ();
|
||||
|
||||
fn run(&self) -> Result<()> {
|
||||
let mut command = Command::new(self.program);
|
||||
command.arg("checkout");
|
||||
command.arg(&self.revision);
|
||||
command.current_dir(&self.path);
|
||||
|
||||
let output = command.output()?;
|
||||
handle_failure("checkout revision", &output)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_os = "windows")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn checkout_revision_success() {
|
||||
CheckoutRevision {
|
||||
program: "./git_checkout_revision",
|
||||
path: "./fake_git".into(),
|
||||
revision: "test-revision".into(),
|
||||
}
|
||||
.run()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checkout_revision_failure() {
|
||||
let result = CheckoutRevision {
|
||||
program: "./git_fails",
|
||||
path: "./fake_git".into(),
|
||||
revision: "test-revision".into(),
|
||||
}
|
||||
.run();
|
||||
|
||||
assert!(result.is_err(), "expected error, got {:?}", result);
|
||||
assert_eq!(
|
||||
"Failed to checkout revision:\n\
|
||||
Status: 1\n\
|
||||
Stdout: some stdout failure message\n\n\
|
||||
Stderr: some stderr failure message\n\n",
|
||||
format!("{}", result.err().unwrap())
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,34 +5,33 @@
|
|||
|
||||
use crate::shell::{handle_failure, output_text, ShellOperation};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
pub struct GetCurrentTag<'a> {
|
||||
pub struct GetCurrentTag {
|
||||
program: &'static str,
|
||||
path: &'a Path,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl<'a> GetCurrentTag<'a> {
|
||||
pub fn new(path: &'a Path) -> GetCurrentTag<'a> {
|
||||
impl GetCurrentTag {
|
||||
pub fn new(path: impl Into<PathBuf>) -> GetCurrentTag {
|
||||
GetCurrentTag {
|
||||
program: "git",
|
||||
path,
|
||||
path: path.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<'a> ShellOperation for GetCurrentTag<'a> {
|
||||
impl ShellOperation for GetCurrentTag {
|
||||
type Output = String;
|
||||
|
||||
async fn spawn(&self) -> Result<String> {
|
||||
fn run(&self) -> Result<String> {
|
||||
let mut command = Command::new(self.program);
|
||||
command.arg("describe");
|
||||
command.arg("--tags");
|
||||
command.current_dir(self.path);
|
||||
let output = tokio::task::spawn_blocking(move || command.output()).await??;
|
||||
command.current_dir(&self.path);
|
||||
|
||||
let output = command.output()?;
|
||||
handle_failure("get current tag", &output)?;
|
||||
let (stdout, _) = output_text(&output);
|
||||
Ok(stdout.trim().into())
|
||||
|
@ -43,11 +42,23 @@ impl<'a> ShellOperation for GetCurrentTag<'a> {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_current_tag_success() {
|
||||
#[test]
|
||||
fn get_current_tag_success() {
|
||||
let tag = GetCurrentTag {
|
||||
program: "./git_describe_tags",
|
||||
path: "./fake_git".as_ref(),
|
||||
path: "./fake_git".into(),
|
||||
}
|
||||
.run()
|
||||
.unwrap();
|
||||
assert_eq!("some-tag", tag);
|
||||
}
|
||||
|
||||
#[cfg(feature = "async-shell")]
|
||||
#[tokio::test]
|
||||
async fn get_current_tag_success_async() {
|
||||
let tag = GetCurrentTag {
|
||||
program: "./git_describe_tags",
|
||||
path: "./fake_git".into(),
|
||||
}
|
||||
.spawn()
|
||||
.await
|
||||
|
@ -55,14 +66,13 @@ mod tests {
|
|||
assert_eq!("some-tag", tag);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_current_tag_failure() {
|
||||
#[test]
|
||||
fn get_current_tag_failure() {
|
||||
let result = GetCurrentTag {
|
||||
program: "./git_fails",
|
||||
path: "./fake_git".as_ref(),
|
||||
path: "./fake_git".into(),
|
||||
}
|
||||
.spawn()
|
||||
.await;
|
||||
.run();
|
||||
|
||||
assert!(result.is_err(), "expected error, got {:?}", result);
|
||||
assert_eq!(
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
use crate::shell::{handle_failure, output_text, ShellOperation};
|
||||
use anyhow::Result;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
pub struct GetLastCommit {
|
||||
program: &'static str,
|
||||
repo_path: PathBuf,
|
||||
}
|
||||
|
||||
impl GetLastCommit {
|
||||
pub fn new(repo_path: impl Into<PathBuf>) -> GetLastCommit {
|
||||
GetLastCommit {
|
||||
program: "git",
|
||||
repo_path: repo_path.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShellOperation for GetLastCommit {
|
||||
type Output = String;
|
||||
|
||||
fn run(&self) -> Result<String> {
|
||||
let mut command = Command::new(self.program);
|
||||
command.arg("rev-parse");
|
||||
command.arg("HEAD");
|
||||
command.current_dir(&self.repo_path);
|
||||
|
||||
let output = command.output()?;
|
||||
handle_failure("get last commit", &output)?;
|
||||
let (stdout, _) = output_text(&output);
|
||||
Ok(stdout.trim().into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_os = "windows")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn get_last_commit_success() {
|
||||
let last_commit = GetLastCommit {
|
||||
program: "./git_revparse_head",
|
||||
repo_path: "./fake_git".into(),
|
||||
}
|
||||
.run()
|
||||
.unwrap();
|
||||
assert_eq!("commithash", last_commit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_last_commit_faijlure() {
|
||||
let result = GetLastCommit {
|
||||
program: "./git_fails",
|
||||
repo_path: "./fake_git".into(),
|
||||
}
|
||||
.run();
|
||||
|
||||
assert!(result.is_err(), "expected error, got {:?}", result);
|
||||
assert_eq!(
|
||||
"Failed to get last commit:\n\
|
||||
Status: 1\n\
|
||||
Stdout: some stdout failure message\n\n\
|
||||
Stderr: some stderr failure message\n\n",
|
||||
format!("{}", result.err().unwrap())
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
/// Returns `true` if this code is being run in GitHub Actions
|
||||
pub fn running_in_github_actions() -> bool {
|
||||
std::env::var("GITHUB_ACTIONS").unwrap_or_default() == "true"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
pub mod git;
|
||||
pub mod github_actions;
|
||||
pub mod package;
|
||||
pub mod shell;
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
pub const SMITHY_PREFIX: &str = "aws-smithy-";
|
||||
pub const SDK_PREFIX: &str = "aws-sdk-";
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum PackageCategory {
|
||||
SmithyRuntime,
|
||||
AwsRuntime,
|
||||
AwsSdk,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl PackageCategory {
|
||||
/// Returns true if the category is `AwsRuntime` or `AwsSdk`
|
||||
pub fn is_sdk(&self) -> bool {
|
||||
matches!(self, PackageCategory::AwsRuntime | PackageCategory::AwsSdk)
|
||||
}
|
||||
|
||||
/// Categorizes a package based on its name
|
||||
pub fn from_package_name(name: &str) -> PackageCategory {
|
||||
if name.starts_with(SMITHY_PREFIX) {
|
||||
PackageCategory::SmithyRuntime
|
||||
} else if name.starts_with(SDK_PREFIX) {
|
||||
PackageCategory::AwsSdk
|
||||
} else if name.starts_with("aws-") {
|
||||
PackageCategory::AwsRuntime
|
||||
} else {
|
||||
PackageCategory::Unknown
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,10 +9,19 @@ use std::process::Output;
|
|||
|
||||
#[async_trait]
|
||||
pub trait ShellOperation {
|
||||
type Output;
|
||||
type Output: Send + 'static;
|
||||
|
||||
/// Runs the command synchronously.
|
||||
fn run(&self) -> Result<Self::Output>;
|
||||
|
||||
/// Runs the command asynchronously.
|
||||
async fn spawn(&self) -> Result<Self::Output>;
|
||||
#[cfg(feature = "async-shell")]
|
||||
async fn spawn(self) -> Result<Self::Output>
|
||||
where
|
||||
Self: Sized + 'static,
|
||||
{
|
||||
tokio::task::spawn_blocking(move || self.run()).await?
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns (stdout, stderr)
|
Loading…
Reference in New Issue