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