use super::validate_dependency;
use crate::utils::{info, remark, success, warning};
use clap::Parser;
use soldeer_core::{
Result,
errors::PublishError,
push::{filter_ignored_files, push_version, validate_name, validate_version},
utils::{canonicalize_sync, check_dotfiles},
};
use std::{env, path::PathBuf, sync::atomic::Ordering};
#[derive(Debug, Clone, Parser, bon::Builder)]
#[allow(clippy::duplicated_attributes)]
#[builder(on(String, into), on(PathBuf, into))]
#[clap(
long_about = "Push a dependency to the soldeer.xyz repository.
You need to be logged in first (soldeer login) or provide the `SOLDEER_API_TOKEN` environment variable with a valid
CLI token generated on soldeer.xyz.
Examples:
- Current directory: soldeer push mypkg~0.1.0
- Custom directory: soldeer push mypkg~0.1.0 /path/to/dep
- Dry run: soldeer push mypkg~0.1.0 --dry-run
To ignore certain files, create a `.soldeerignore` file in the root of the project and add the files you want to ignore. The `.soldeerignore` uses the same syntax as `.gitignore`.",
after_help = "For more information, read the README.md"
)]
#[non_exhaustive]
pub struct Push {
#[arg(value_parser = validate_dependency, value_name = "DEPENDENCY>~<VERSION")]
pub dependency: String,
pub path: Option<PathBuf>,
#[arg(short, long, default_value_t = false)]
#[builder(default)]
pub dry_run: bool,
#[arg(long, default_value_t = false)]
#[builder(default)]
pub skip_warnings: bool,
}
pub(crate) async fn push_command(cmd: Push) -> Result<()> {
let path = cmd.path.unwrap_or(env::current_dir()?);
let path = canonicalize_sync(&path)?;
let files_to_copy: Vec<PathBuf> = filter_ignored_files(&path);
if !cmd.dry_run &&
!cmd.skip_warnings &&
check_dotfiles(&files_to_copy) &&
!prompt_user_for_confirmation()?
{
return Err(PublishError::UserAborted.into());
}
if cmd.dry_run {
remark!("Running in dry-run mode, a zip file will be created for inspection");
}
if cmd.skip_warnings {
warning!("Sensitive file warnings are being ignored as requested");
}
let (dependency_name, dependency_version) =
cmd.dependency.split_once('~').expect("dependency string should have name and version");
validate_name(dependency_name)?;
validate_version(dependency_version)?;
if let Some(zip_path) =
push_version(dependency_name, dependency_version, path, &files_to_copy, cmd.dry_run).await?
{
info!(format!("Zip file created at {}", zip_path.to_string_lossy()));
} else {
success!("Pushed to repository!");
}
Ok(())
}
fn prompt_user_for_confirmation() -> Result<bool> {
remark!("You are about to include some sensitive files in this version");
info!(
"If you are not sure which files will be included, you can run the command with `--dry-run`and inspect the generated zip file."
);
if crate::TUI_ENABLED.load(Ordering::Relaxed) {
cliclack::confirm("Do you want to continue?")
.interact()
.map_err(|e| PublishError::IOError { path: PathBuf::new(), source: e }.into())
} else {
Ok(true)
}
}