xtask: Add dry-run option for release task
This commit is contained in:
		
							parent
							
								
									1f23e8abcb
								
							
						
					
					
						commit
						c647d39c9e
					
				@ -29,14 +29,16 @@ pub struct Package {
 | 
			
		||||
 | 
			
		||||
impl Package {
 | 
			
		||||
    /// Update the version of this crate.
 | 
			
		||||
    pub fn update_version(&mut self, version: &Version) -> Result<()> {
 | 
			
		||||
    pub fn update_version(&mut self, version: &Version, dry_run: bool) -> Result<()> {
 | 
			
		||||
        println!("Updating {} to version {}…", self.name, version);
 | 
			
		||||
 | 
			
		||||
        if !dry_run {
 | 
			
		||||
            let mut document = read_file(&self.manifest_path)?.parse::<Document>()?;
 | 
			
		||||
 | 
			
		||||
            document["package"]["version"] = value(version.to_string());
 | 
			
		||||
 | 
			
		||||
            write_file(&self.manifest_path, document.to_string())?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.version = version.clone();
 | 
			
		||||
 | 
			
		||||
@ -45,13 +47,14 @@ impl Package {
 | 
			
		||||
 | 
			
		||||
    /// Update the version of this crate in dependant crates' manifests, with the given version
 | 
			
		||||
    /// prefix.
 | 
			
		||||
    pub(crate) fn update_dependants(&self, metadata: &Metadata) -> Result<()> {
 | 
			
		||||
    pub(crate) fn update_dependants(&self, metadata: &Metadata, dry_run: bool) -> Result<()> {
 | 
			
		||||
        for package in metadata.packages.iter().filter(|p| {
 | 
			
		||||
            p.manifest_path.starts_with(&metadata.workspace_root)
 | 
			
		||||
                && p.dependencies.iter().any(|d| d.name == self.name)
 | 
			
		||||
        }) {
 | 
			
		||||
            println!("Updating dependency in {} crate…", package.name);
 | 
			
		||||
 | 
			
		||||
            if !dry_run {
 | 
			
		||||
                let mut document = read_file(&package.manifest_path)?.parse::<Document>()?;
 | 
			
		||||
 | 
			
		||||
                let version = if !self.version.pre.is_empty()
 | 
			
		||||
@ -74,6 +77,7 @@ impl Package {
 | 
			
		||||
 | 
			
		||||
                write_file(&package.manifest_path, document.to_string())?;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
@ -139,7 +143,7 @@ impl Package {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Publish this package on crates.io.
 | 
			
		||||
    pub fn publish(&self, client: &HttpClient) -> Result<bool> {
 | 
			
		||||
    pub fn publish(&self, client: &HttpClient, dry_run: bool) -> Result<bool> {
 | 
			
		||||
        println!("Publishing {} {} on crates.io…", self.name, self.version);
 | 
			
		||||
        let _dir = pushd(&self.manifest_path.parent().unwrap())?;
 | 
			
		||||
 | 
			
		||||
@ -150,7 +154,9 @@ impl Package {
 | 
			
		||||
                Err("Release interrupted by user.".into())
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if !dry_run {
 | 
			
		||||
                cmd!("cargo publish").run()?;
 | 
			
		||||
            }
 | 
			
		||||
            Ok(true)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -54,7 +54,7 @@ fn main() -> Result<()> {
 | 
			
		||||
        Command::Doc(doc) => doc.run(),
 | 
			
		||||
        #[cfg(feature = "default")]
 | 
			
		||||
        Command::Release(args) => {
 | 
			
		||||
            let mut task = ReleaseTask::new(args.package, args.version)?;
 | 
			
		||||
            let mut task = ReleaseTask::new(args.package, args.version, args.dry_run)?;
 | 
			
		||||
            task.run()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,10 @@ pub struct ReleaseArgs {
 | 
			
		||||
 | 
			
		||||
    /// The new version of the crate
 | 
			
		||||
    pub version: Version,
 | 
			
		||||
 | 
			
		||||
    /// List the steps but don't actually change anything
 | 
			
		||||
    #[clap(long)]
 | 
			
		||||
    pub dry_run: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Task to create a new release of the given crate.
 | 
			
		||||
@ -44,11 +48,14 @@ pub struct ReleaseTask {
 | 
			
		||||
 | 
			
		||||
    /// The github configuration required to publish a release.
 | 
			
		||||
    config: GithubConfig,
 | 
			
		||||
 | 
			
		||||
    /// List the steps but don't actually change anything
 | 
			
		||||
    pub dry_run: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ReleaseTask {
 | 
			
		||||
    /// Create a new `ReleaseTask` with the given `name` and `version`.
 | 
			
		||||
    pub(crate) fn new(name: String, version: Version) -> Result<Self> {
 | 
			
		||||
    pub(crate) fn new(name: String, version: Version, dry_run: bool) -> Result<Self> {
 | 
			
		||||
        let metadata = Metadata::load()?;
 | 
			
		||||
 | 
			
		||||
        let package = metadata
 | 
			
		||||
@ -62,17 +69,15 @@ impl ReleaseTask {
 | 
			
		||||
 | 
			
		||||
        let http_client = HttpClient::new()?;
 | 
			
		||||
 | 
			
		||||
        Ok(Self { metadata, package, version, http_client, config })
 | 
			
		||||
        Ok(Self { metadata, package, version, http_client, config, dry_run })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Run the task to effectively create a release.
 | 
			
		||||
    pub(crate) fn run(&mut self) -> Result<()> {
 | 
			
		||||
        if self.package.name == "ruma-macros" {
 | 
			
		||||
            return Err(
 | 
			
		||||
                "The ruma-macros crate is always released together with the ruma-common crate.\n\
 | 
			
		||||
                 To release both, simply run\n\
 | 
			
		||||
                 \n\
 | 
			
		||||
                 cargo xtask release ruma-common"
 | 
			
		||||
                "The ruma-macros crate is always released together with the ruma-common crate. \
 | 
			
		||||
                 To release both, simply run `cargo xtask release ruma-common`"
 | 
			
		||||
                    .into(),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
@ -123,14 +128,14 @@ impl ReleaseTask {
 | 
			
		||||
            if let Some(m) = macros.as_mut() {
 | 
			
		||||
                println!("Updating version of ruma-macros crate…");
 | 
			
		||||
 | 
			
		||||
                m.update_version(&self.version)?;
 | 
			
		||||
                m.update_dependants(&self.metadata)?;
 | 
			
		||||
                m.update_version(&self.version, self.dry_run)?;
 | 
			
		||||
                m.update_dependants(&self.metadata, self.dry_run)?;
 | 
			
		||||
 | 
			
		||||
                println!("Resuming release of {}…", self.title());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            self.package.update_version(&self.version)?;
 | 
			
		||||
            self.package.update_dependants(&self.metadata)?;
 | 
			
		||||
            self.package.update_version(&self.version, self.dry_run)?;
 | 
			
		||||
            self.package.update_dependants(&self.metadata, self.dry_run)?;
 | 
			
		||||
            true
 | 
			
		||||
        } else if !ask_yes_no(&format!(
 | 
			
		||||
            "Package is already version {}. Skip creating a commit and continue?",
 | 
			
		||||
@ -141,16 +146,16 @@ impl ReleaseTask {
 | 
			
		||||
            false
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let changes = &self.package.changes(!prerelease)?;
 | 
			
		||||
        let changes = &self.package.changes(!prerelease && !self.dry_run)?;
 | 
			
		||||
 | 
			
		||||
        if create_commit {
 | 
			
		||||
            self.commit()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let Some(m) = macros {
 | 
			
		||||
            let published = m.publish(&self.http_client)?;
 | 
			
		||||
            let published = m.publish(&self.http_client, self.dry_run)?;
 | 
			
		||||
 | 
			
		||||
            if published {
 | 
			
		||||
            if published && !self.dry_run {
 | 
			
		||||
                // Crate was published, instead of publishing skipped (because release already
 | 
			
		||||
                // existed).
 | 
			
		||||
                println!("Waiting 20 seconds for the release to make it into the crates.io index…");
 | 
			
		||||
@ -158,12 +163,14 @@ impl ReleaseTask {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.package.publish(&self.http_client)?;
 | 
			
		||||
        self.package.publish(&self.http_client, self.dry_run)?;
 | 
			
		||||
 | 
			
		||||
        let branch = cmd!("git rev-parse --abbrev-ref HEAD").read()?;
 | 
			
		||||
        if publish_only {
 | 
			
		||||
            println!("Pushing to remote repository…");
 | 
			
		||||
            if !self.dry_run {
 | 
			
		||||
                cmd!("git push {remote} {branch}").run()?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            println!("Crate published successfully!");
 | 
			
		||||
            return Ok(());
 | 
			
		||||
@ -171,16 +178,20 @@ impl ReleaseTask {
 | 
			
		||||
 | 
			
		||||
        let tag = &self.tag_name();
 | 
			
		||||
 | 
			
		||||
        println!("Creating git tag…");
 | 
			
		||||
        println!("Creating git tag '{tag}'…");
 | 
			
		||||
        if cmd!("git tag -l {tag}").read()?.is_empty() {
 | 
			
		||||
            if !self.dry_run {
 | 
			
		||||
                cmd!("git tag -s {tag} -m {title} -m {changes}").read()?;
 | 
			
		||||
            }
 | 
			
		||||
        } else if !ask_yes_no("This tag already exists. Skip this step and continue?")? {
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        println!("Pushing to remote repository…");
 | 
			
		||||
        if cmd!("git ls-remote --tags {remote} {tag}").read()?.is_empty() {
 | 
			
		||||
            if !self.dry_run {
 | 
			
		||||
                cmd!("git push {remote} {branch} {tag}").run()?;
 | 
			
		||||
            }
 | 
			
		||||
        } else if !ask_yes_no("This tag has already been pushed. Skip this step and continue?")? {
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
@ -198,7 +209,9 @@ impl ReleaseTask {
 | 
			
		||||
        })
 | 
			
		||||
        .to_string();
 | 
			
		||||
 | 
			
		||||
        if !self.dry_run {
 | 
			
		||||
            self.release(request_body)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        println!("Release created successfully!");
 | 
			
		||||
 | 
			
		||||
@ -231,6 +244,7 @@ impl ReleaseTask {
 | 
			
		||||
    fn commit(&self) -> Result<()> {
 | 
			
		||||
        let stdin = stdin();
 | 
			
		||||
 | 
			
		||||
        if !self.dry_run {
 | 
			
		||||
            let instructions = "Ready to commit the changes. [continue/abort/diff]: ";
 | 
			
		||||
            print!("{}", instructions);
 | 
			
		||||
            stdout().flush()?;
 | 
			
		||||
@ -263,11 +277,15 @@ impl ReleaseTask {
 | 
			
		||||
 | 
			
		||||
                input.clear();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let message = format!("Release {}", self.title());
 | 
			
		||||
 | 
			
		||||
        println!("Creating commit…");
 | 
			
		||||
        println!("Creating commit with message '{message}'…");
 | 
			
		||||
 | 
			
		||||
        if !self.dry_run {
 | 
			
		||||
            cmd!("git commit -a -m {message}").read()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user