Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement initial tool for publishing to crates.io #251

Merged
merged 6 commits into from
Oct 18, 2021
Merged

Implement initial tool for publishing to crates.io #251

merged 6 commits into from
Oct 18, 2021

Conversation

jdisanti
Copy link
Contributor

This is an initial implementation of a tool to publish the SDK to crates.io. It has two subcommands:

  • fix-manifests: This is to be run after importing the latest generated code from smithy-rs. It will add versions to all path dependencies for all crates.
  • publish: This will be run when ready to actually publish to crates.io. It figures out the correct order to publish the crates in, chunks them into batches, and runs them with some throttled concurrency. It currently doesn't retry on failure, but this can be added later.

I tested everything works correctly except for the final publish, which, can't be tested until we actually publish. Doing a dry-run publish succeeds for the first few crates that don't have any path dependencies.

Sample output of the publish command:

Oct 12 18:44:08.509  INFO publisher::subcommand::publish: Discovering crates to publish...
Oct 12 18:44:09.432  INFO publisher::subcommand::publish: Crates discovered.
Publish plan:
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/protocol-test-helpers"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-async"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-types"]: cargo publish --dry-run
  wait
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-eventstream"]: cargo publish --dry-run
  wait
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/aws-sigv4"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/aws-types"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-http"]: cargo publish --dry-run
  wait
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-http-tower"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-json"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-query"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-xml"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/aws-endpoint"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/aws-auth"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/aws-http"]: cargo publish --dry-run
  wait
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-client"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/aws-sig-auth"]: cargo publish --dry-run
  wait
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/aws-hyper"]: cargo publish --dry-run
  wait
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/sts"]: cargo publish --dry-run
  wait
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/aws-config"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/accessanalyzer"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/account"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/acm"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/acmpca"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/alexaforbusiness"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/amp"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/amplify"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/amplifybackend"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/apigateway"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/apigatewaymanagement"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/apigatewayv2"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/appconfig"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/appflow"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/appintegrations"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/applicationautoscaling"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/applicationcostprofiler"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/applicationdiscovery"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/applicationinsights"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/appmesh"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/apprunner"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/appstream"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/appsync"]: cargo publish --dry-run
  [in "/home/jdisanti/src/aws-sdk-rust/sdk/athena"]: cargo publish --dry-run

... snip ...

Continuing will publish to crates.io. Do you wish to continue? yes
Oct 12 18:44:10.765  INFO publisher::subcommand::publish: Executing `[in "/home/jdisanti/src/aws-sdk-rust/sdk/protocol-test-helpers"]: cargo publish --dry-run`...
Oct 12 18:44:10.766  INFO publisher::subcommand::publish: Executing `[in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-async"]: cargo publish --dry-run`...
Oct 12 18:44:10.766  INFO publisher::subcommand::publish: Executing `[in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-types"]: cargo publish --dry-run`...
Oct 12 18:44:44.273  INFO publisher::subcommand::publish: Success: `[in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-types"]: cargo publish --dry-run`
Oct 12 18:44:49.941  INFO publisher::subcommand::publish: Success: `[in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-async"]: cargo publish --dry-run`
Oct 12 18:44:52.607  INFO publisher::subcommand::publish: Success: `[in "/home/jdisanti/src/aws-sdk-rust/sdk/protocol-test-helpers"]: cargo publish --dry-run`
Oct 12 18:44:52.608  INFO publisher::subcommand::publish: Executing `[in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-eventstream"]: cargo publish --dry-run`...
Error: Cargo publish failed:
Plan: [in "/home/jdisanti/src/aws-sdk-rust/sdk/smithy-eventstream"]: cargo publish --dry-run
Status: exit status: 101
Stdout: 
Stderr:     Updating crates.io index
warning: manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
   Packaging smithy-eventstream v0.1.0 (/home/jdisanti/src/aws-sdk-rust/sdk/smithy-eventstream)
   Verifying smithy-eventstream v0.1.0 (/home/jdisanti/src/aws-sdk-rust/sdk/smithy-eventstream)
error: failed to verify package tarball

Caused by:
  no matching package named `smithy-types` found
  location searched: registry `https://github.com/rust-lang/crates.io-index`
  perhaps you meant: smithy_types
  required by package `smithy-eventstream v0.1.0 (/home/jdisanti/src/aws-sdk-rust/sdk/target/package/smithy-eventstream-0.1.0)`

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@jdisanti jdisanti requested review from rcoh and Velfi October 13, 2021 02:04
Comment on lines 18 to 19
pub const REPO_NAME: &'static str = "aws-sdk-rust";
pub const REPO_CRATE_PATH: &'static str = "sdk";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noting the static lifetime is no longer required by the compiler, &str is fine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's going to take me a long time to break that habit 😅

use tracing::info;

const BACKOFF: Duration = Duration::from_millis(30);
const MAX_CONCURRENCY: usize = 4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking that up, that's good to know. I think I'm going to cap this at the number of physical CPUs since cargo publish seems to actually invoke rustc.

info!("Discovering crates to publish...");
let repo = discover_repository(REPO_NAME, REPO_CRATE_PATH)?;
let batches = discover_package_batches(Fs::Real, &repo.crates_root).await?;
info!("Crates discovered.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'd be cool if this could print the number of runtime crates and number of sdk crates just as a sanity check helper

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea! Added.

Copy link
Contributor

@rcoh rcoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! a really impressive piece of work, excited to see it in action!

Comment on lines +36 to +40
#[derive(Default)]
pub struct Cmd {
parts: Vec<String>,
working_dir: Option<PathBuf>,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow...is there no library that does this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started off using async-process, but it was more complicated than I wanted to access stdout/stderr with that.

}

/// Runs the command asynchronously.
pub async fn spawn(mut self) -> Result<Output> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason to do this async? Seems like we may want to block on these commands running

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I see, we use a semaphore later. 👍🏻


/// Validates that all of the publishable crates use consistent version numbers
/// across all of their local dependencies.
fn validate_packages(packages: &Vec<Package>) -> Result<()> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clippy won't let you do this, &[Package]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I should run clippy on this... and also add it to CI 😄

* SPDX-License-Identifier: Apache-2.0.
*/

//! Repository discovery.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add the word "git" here and mention that it's on the local file system? wasn't clear to me what kind of repository this was talking about

Comment on lines +54 to +57
enum Error {
#[error("dependency cycle detected")]
DependencyCycle,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, this should be impossible because cargo won't allow it

Copy link
Contributor

@rcoh rcoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@rcoh rcoh merged commit c5d6c8d into awslabs:main Oct 18, 2021
@jdisanti jdisanti deleted the publishing-tool branch October 19, 2021 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants