mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 19:10:35 +00:00
feat: publish members when publishing workspace
This commit is contained in:
parent
9a64a12f8e
commit
fa00a97f8b
6 changed files with 57 additions and 25 deletions
|
@ -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/),
|
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).
|
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
|
### Fixed
|
||||||
- Add feature gates to `wally-compat` specific code in init command by @daimond113
|
- Add feature gates to `wally-compat` specific code in init command by @daimond113
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ impl InstallCommand {
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"\n{}\n",
|
"\n{}\n",
|
||||||
format!("[now installing {}]", manifest.name)
|
format!("[now installing {} {}]", manifest.name, manifest.target)
|
||||||
.bold()
|
.bold()
|
||||||
.on_bright_black()
|
.on_bright_black()
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use tempfile::tempfile;
|
use tempfile::tempfile;
|
||||||
|
|
||||||
use crate::cli::up_to_date_lockfile;
|
use crate::cli::{run_on_workspace_members, up_to_date_lockfile};
|
||||||
use pesde::{
|
use pesde::{
|
||||||
manifest::{target::Target, DependencyType},
|
manifest::{target::Target, DependencyType},
|
||||||
scripts::ScriptName,
|
scripts::ScriptName,
|
||||||
|
@ -23,19 +23,30 @@ use pesde::{
|
||||||
Project, DEFAULT_INDEX_NAME, MANIFEST_FILE_NAME,
|
Project, DEFAULT_INDEX_NAME, MANIFEST_FILE_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args, Copy, Clone)]
|
||||||
pub struct PublishCommand {
|
pub struct PublishCommand {
|
||||||
/// Whether to output a tarball instead of publishing
|
/// Whether to output a tarball instead of publishing
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
|
|
||||||
|
/// Agree to all prompts
|
||||||
|
#[arg(short, long)]
|
||||||
|
yes: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PublishCommand {
|
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
|
let mut manifest = project
|
||||||
.deser_manifest()
|
.deser_manifest()
|
||||||
.context("failed to read manifest")?;
|
.context("failed to read manifest")?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"\n{}\n",
|
||||||
|
format!("[now publishing {} {}]", manifest.name, manifest.target)
|
||||||
|
.bold()
|
||||||
|
.on_bright_black()
|
||||||
|
);
|
||||||
|
|
||||||
if manifest.private {
|
if manifest.private {
|
||||||
println!("{}", "package is private, cannot publish".red().bold());
|
println!("{}", "package is private, cannot publish".red().bold());
|
||||||
|
|
||||||
|
@ -54,7 +65,7 @@ impl PublishCommand {
|
||||||
anyhow::bail!("no build files found in target");
|
anyhow::bail!("no build files found in target");
|
||||||
}
|
}
|
||||||
|
|
||||||
match up_to_date_lockfile(&project)? {
|
match up_to_date_lockfile(project)? {
|
||||||
Some(lockfile) => {
|
Some(lockfile) => {
|
||||||
if lockfile
|
if lockfile
|
||||||
.graph
|
.graph
|
||||||
|
@ -313,7 +324,7 @@ impl PublishCommand {
|
||||||
}
|
}
|
||||||
DependencySpecifiers::Workspace(spec) => {
|
DependencySpecifiers::Workspace(spec) => {
|
||||||
let pkg_ref = WorkspacePackageSource
|
let pkg_ref = WorkspacePackageSource
|
||||||
.resolve(spec, &project, target_kind)
|
.resolve(spec, project, target_kind)
|
||||||
.context("failed to resolve workspace package")?
|
.context("failed to resolve workspace package")?
|
||||||
.1
|
.1
|
||||||
.pop_last()
|
.pop_last()
|
||||||
|
@ -410,7 +421,10 @@ impl PublishCommand {
|
||||||
display_includes.into_iter().collect::<Vec<_>>().join(", ")
|
display_includes.into_iter().collect::<Vec<_>>().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());
|
println!("\n{}", "publish aborted".red().bold());
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -447,10 +461,10 @@ impl PublishCommand {
|
||||||
.clone(),
|
.clone(),
|
||||||
);
|
);
|
||||||
source
|
source
|
||||||
.refresh(&project)
|
.refresh(project)
|
||||||
.context("failed to refresh source")?;
|
.context("failed to refresh source")?;
|
||||||
let config = source
|
let config = source
|
||||||
.config(&project)
|
.config(project)
|
||||||
.context("failed to get source config")?;
|
.context("failed to get source config")?;
|
||||||
|
|
||||||
if archive.len() > config.max_archive_size {
|
if archive.len() > config.max_archive_size {
|
||||||
|
@ -497,30 +511,36 @@ impl PublishCommand {
|
||||||
match status {
|
match status {
|
||||||
StatusCode::CONFLICT => {
|
StatusCode::CONFLICT => {
|
||||||
println!("{}", "package version already exists".red().bold());
|
println!("{}", "package version already exists".red().bold());
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
StatusCode::FORBIDDEN => {
|
StatusCode::FORBIDDEN => {
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
"unauthorized to publish under this scope".red().bold()
|
"unauthorized to publish under this scope".red().bold()
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
StatusCode::BAD_REQUEST => {
|
StatusCode::BAD_REQUEST => {
|
||||||
println!("{}: {text}", "invalid package".red().bold());
|
println!("{}: {text}", "invalid package".red().bold());
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
code if !code.is_success() => {
|
code if !code.is_success() => {
|
||||||
anyhow::bail!("failed to publish package: {code} ({text})");
|
anyhow::bail!("failed to publish package: {code} ({text})");
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("{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(|_| ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::cli::{download_graph, run_on_workspace_members};
|
use crate::cli::{download_graph, run_on_workspace_members};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
use colored::Colorize;
|
||||||
use indicatif::MultiProgress;
|
use indicatif::MultiProgress;
|
||||||
use pesde::{lockfile::Lockfile, Project};
|
use pesde::{lockfile::Lockfile, Project};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
@ -25,6 +26,13 @@ impl UpdateCommand {
|
||||||
.deser_manifest()
|
.deser_manifest()
|
||||||
.context("failed to read manifest")?;
|
.context("failed to read manifest")?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"\n{}\n",
|
||||||
|
format!("[now updating {} {}]", manifest.name, manifest.target)
|
||||||
|
.bold()
|
||||||
|
.on_bright_black()
|
||||||
|
);
|
||||||
|
|
||||||
let graph = project
|
let graph = project
|
||||||
.dependency_graph(None, &mut refreshed_sources)
|
.dependency_graph(None, &mut refreshed_sources)
|
||||||
.context("failed to build dependency graph")?;
|
.context("failed to build dependency graph")?;
|
||||||
|
|
|
@ -272,8 +272,8 @@ pub fn run_on_workspace_members(
|
||||||
) -> anyhow::Result<BTreeMap<PackageName, BTreeMap<TargetKind, RelativePathBuf>>> {
|
) -> anyhow::Result<BTreeMap<PackageName, BTreeMap<TargetKind, RelativePathBuf>>> {
|
||||||
Ok(match project.workspace_dir() {
|
Ok(match project.workspace_dir() {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
// this might seem counterintuitive, but remember that the workspace
|
// this might seem counterintuitive, but remember that
|
||||||
// is the package_dir when the user isn't in a member package
|
// the presence of a workspace dir means that this project is a member of one
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
None => project
|
None => project
|
||||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -130,27 +130,27 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the package directory
|
/// The directory of the package
|
||||||
pub fn package_dir(&self) -> &Path {
|
pub fn package_dir(&self) -> &Path {
|
||||||
&self.package_dir
|
&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> {
|
pub fn workspace_dir(&self) -> Option<&Path> {
|
||||||
self.workspace_dir.as_deref()
|
self.workspace_dir.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the data directory
|
/// The directory to store general-purpose data
|
||||||
pub fn data_dir(&self) -> &Path {
|
pub fn data_dir(&self) -> &Path {
|
||||||
&self.data_dir
|
&self.data_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the authentication configuration
|
/// The authentication configuration
|
||||||
pub fn auth_config(&self) -> &AuthConfig {
|
pub fn auth_config(&self) -> &AuthConfig {
|
||||||
&self.auth_config
|
&self.auth_config
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the CAS (content-addressable storage) directory
|
/// The CAS (content-addressable storage) directory
|
||||||
pub fn cas_dir(&self) -> &Path {
|
pub fn cas_dir(&self) -> &Path {
|
||||||
&self.cas_dir
|
&self.cas_dir
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue