diff --git a/CHANGELOG.md b/CHANGELOG.md index fc64736..661f732 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] - 2024-10-07 +## [Unreleased] +### Added +- Add `yes` argument to skip all prompts in publish command by @daimond113 +- Publish all workspace members when publishing a workspace by @daimond113 + ### Fixed - Add feature gates to `wally-compat` specific code in init command by @daimond113 diff --git a/src/cli/commands/install.rs b/src/cli/commands/install.rs index ccfd104..32ccdef 100644 --- a/src/cli/commands/install.rs +++ b/src/cli/commands/install.rs @@ -131,7 +131,7 @@ impl InstallCommand { println!( "\n{}\n", - format!("[now installing {}]", manifest.name) + format!("[now installing {} {}]", manifest.name, manifest.target) .bold() .on_bright_black() ); diff --git a/src/cli/commands/publish.rs b/src/cli/commands/publish.rs index a13680c..28cccc4 100644 --- a/src/cli/commands/publish.rs +++ b/src/cli/commands/publish.rs @@ -9,7 +9,7 @@ use std::{ }; use tempfile::tempfile; -use crate::cli::up_to_date_lockfile; +use crate::cli::{run_on_workspace_members, up_to_date_lockfile}; use pesde::{ manifest::{target::Target, DependencyType}, scripts::ScriptName, @@ -23,19 +23,30 @@ use pesde::{ Project, DEFAULT_INDEX_NAME, MANIFEST_FILE_NAME, }; -#[derive(Debug, Args)] +#[derive(Debug, Args, Copy, Clone)] pub struct PublishCommand { /// Whether to output a tarball instead of publishing #[arg(short, long)] dry_run: bool, + + /// Agree to all prompts + #[arg(short, long)] + yes: bool, } impl PublishCommand { - pub fn run(self, project: Project, reqwest: reqwest::blocking::Client) -> anyhow::Result<()> { + fn run_impl(self, project: &Project, reqwest: reqwest::blocking::Client) -> anyhow::Result<()> { let mut manifest = project .deser_manifest() .context("failed to read manifest")?; + println!( + "\n{}\n", + format!("[now publishing {} {}]", manifest.name, manifest.target) + .bold() + .on_bright_black() + ); + if manifest.private { println!("{}", "package is private, cannot publish".red().bold()); @@ -54,7 +65,7 @@ impl PublishCommand { anyhow::bail!("no build files found in target"); } - match up_to_date_lockfile(&project)? { + match up_to_date_lockfile(project)? { Some(lockfile) => { if lockfile .graph @@ -313,7 +324,7 @@ impl PublishCommand { } DependencySpecifiers::Workspace(spec) => { let pkg_ref = WorkspacePackageSource - .resolve(spec, &project, target_kind) + .resolve(spec, project, target_kind) .context("failed to resolve workspace package")? .1 .pop_last() @@ -410,7 +421,10 @@ impl PublishCommand { display_includes.into_iter().collect::>().join(", ") ); - if !self.dry_run && !inquire::Confirm::new("is this information correct?").prompt()? { + if !self.dry_run + && !self.yes + && !inquire::Confirm::new("is this information correct?").prompt()? + { println!("\n{}", "publish aborted".red().bold()); return Ok(()); @@ -447,10 +461,10 @@ impl PublishCommand { .clone(), ); source - .refresh(&project) + .refresh(project) .context("failed to refresh source")?; let config = source - .config(&project) + .config(project) .context("failed to get source config")?; if archive.len() > config.max_archive_size { @@ -497,30 +511,36 @@ impl PublishCommand { match status { StatusCode::CONFLICT => { println!("{}", "package version already exists".red().bold()); - - Ok(()) } StatusCode::FORBIDDEN => { println!( "{}", "unauthorized to publish under this scope".red().bold() ); - - Ok(()) } StatusCode::BAD_REQUEST => { println!("{}: {text}", "invalid package".red().bold()); - - Ok(()) } code if !code.is_success() => { anyhow::bail!("failed to publish package: {code} ({text})"); } _ => { println!("{text}"); - - Ok(()) } } + + Ok(()) + } + + pub fn run(self, project: Project, reqwest: reqwest::blocking::Client) -> anyhow::Result<()> { + let result = self.run_impl(&project, reqwest.clone()); + if project.workspace_dir().is_some() { + return result; + } else if let Err(result) = result { + println!("an error occurred publishing workspace root: {result}"); + } + + run_on_workspace_members(&project, |project| self.run_impl(&project, reqwest.clone())) + .map(|_| ()) } } diff --git a/src/cli/commands/update.rs b/src/cli/commands/update.rs index 1da5a13..fd139b9 100644 --- a/src/cli/commands/update.rs +++ b/src/cli/commands/update.rs @@ -1,6 +1,7 @@ use crate::cli::{download_graph, run_on_workspace_members}; use anyhow::Context; use clap::Args; +use colored::Colorize; use indicatif::MultiProgress; use pesde::{lockfile::Lockfile, Project}; use std::collections::HashSet; @@ -25,6 +26,13 @@ impl UpdateCommand { .deser_manifest() .context("failed to read manifest")?; + println!( + "\n{}\n", + format!("[now updating {} {}]", manifest.name, manifest.target) + .bold() + .on_bright_black() + ); + let graph = project .dependency_graph(None, &mut refreshed_sources) .context("failed to build dependency graph")?; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 02de800..f146b4f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -272,8 +272,8 @@ pub fn run_on_workspace_members( ) -> anyhow::Result>> { Ok(match project.workspace_dir() { Some(_) => { - // this might seem counterintuitive, but remember that the workspace - // is the package_dir when the user isn't in a member package + // this might seem counterintuitive, but remember that + // the presence of a workspace dir means that this project is a member of one Default::default() } None => project diff --git a/src/lib.rs b/src/lib.rs index c974532..e3022dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,27 +130,27 @@ impl Project { } } - /// Access the package directory + /// The directory of the package pub fn package_dir(&self) -> &Path { &self.package_dir } - /// Access the workspace directory + /// The directory of the workspace this package belongs to, if any pub fn workspace_dir(&self) -> Option<&Path> { self.workspace_dir.as_deref() } - /// Access the data directory + /// The directory to store general-purpose data pub fn data_dir(&self) -> &Path { &self.data_dir } - /// Access the authentication configuration + /// The authentication configuration pub fn auth_config(&self) -> &AuthConfig { &self.auth_config } - /// Access the CAS (content-addressable storage) directory + /// The CAS (content-addressable storage) directory pub fn cas_dir(&self) -> &Path { &self.cas_dir }