use std::path::PathBuf;
use anyhow::{
Context,
Result,
};
use async_fs_io::write_bytes;
use cargo_plugin_utils::common::find_package;
use clap::Parser;
#[derive(Parser, Debug)]
pub struct CurrentArgs {
#[arg(long)]
manifest_path: Option<PathBuf>,
#[arg(long, default_value = "version")]
format: String,
#[arg(long, env = "GITHUB_OUTPUT")]
github_output: Option<String>,
}
pub async fn current(args: CurrentArgs) -> Result<()> {
let mut logger = cargo_plugin_utils::logger::Logger::new();
logger.status("Reading", "package version");
let package = find_package(args.manifest_path.as_deref())?;
let version = package.version.to_string();
logger.finish();
match args.format.as_str() {
"version" => println!("{}", version),
"json" => println!("{{\"version\":\"{}\"}}", version),
"github-actions" => {
let output_file = args.github_output.as_deref().unwrap_or("/dev/stdout");
let output = format!("version={}\n", version);
write_bytes(output_file, output.as_bytes())
.await
.with_context(|| format!("Failed to write to {}", output_file))?;
}
_ => anyhow::bail!("Invalid format: {}", args.format),
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
async fn create_temp_cargo_project(content: &str) -> async_fs_io::TempDir {
let dir = async_fs_io::TempDir::create(std::env::temp_dir())
.await
.unwrap();
let manifest_path = dir.path().join("Cargo.toml");
async_fs_io::write_bytes(&manifest_path, content.as_bytes())
.await
.unwrap();
let src_dir = dir.path().join("src");
async_fs_io::ensure_dir(&src_dir).await.unwrap();
async_fs_io::write_bytes(src_dir.join("lib.rs"), b"// Test library\n")
.await
.unwrap();
dir
}
#[tokio::test]
async fn test_current_workspace_version() {
let _dir = async_fs_io::TempDir::create(std::env::temp_dir())
.await
.unwrap();
async_fs_io::write_bytes(
_dir.path().join("Cargo.toml"),
br#"
[workspace.package]
version = "0.1.2"
[workspace]
members = ["member1"]
"#,
)
.await
.unwrap();
let member_dir = _dir.path().join("member1");
async_fs_io::ensure_dir(member_dir.join("src"))
.await
.unwrap();
async_fs_io::write_bytes(
member_dir.join("Cargo.toml"),
br#"
[package]
name = "member1"
version.workspace = true
"#,
)
.await
.unwrap();
async_fs_io::write_bytes(member_dir.join("src").join("lib.rs"), b"// Test library\n")
.await
.unwrap();
let manifest_path = member_dir.join("Cargo.toml");
let args = CurrentArgs {
manifest_path: Some(manifest_path),
format: "version".to_string(),
github_output: None,
};
assert!(current(args).await.is_ok());
}
#[tokio::test]
async fn test_current_package_version() {
let _dir = create_temp_cargo_project(
r#"
[package]
name = "test"
version = "1.2.3"
"#,
)
.await;
let manifest_path = _dir.path().join("Cargo.toml");
let args = CurrentArgs {
manifest_path: Some(manifest_path.clone()),
format: "version".to_string(),
github_output: None,
};
let result = current(args).await;
if let Err(e) = &result {
eprintln!("Error in test_current_package_version: {}", e);
eprintln!("Manifest path: {:?}", manifest_path);
}
assert!(result.is_ok());
}
#[tokio::test]
async fn test_current_json_format() {
let _dir = create_temp_cargo_project(
r#"
[package]
name = "test"
version = "0.5.0"
"#,
)
.await;
let manifest_path = _dir.path().join("Cargo.toml");
let args = CurrentArgs {
manifest_path: Some(manifest_path),
format: "json".to_string(),
github_output: None,
};
assert!(current(args).await.is_ok());
}
#[tokio::test]
async fn test_current_github_actions_format() {
let _dir = create_temp_cargo_project(
r#"
[package]
name = "test"
version = "2.0.0"
"#,
)
.await;
let manifest_path = _dir.path().join("Cargo.toml");
let output_file = async_fs_io::TempFile::create(std::env::temp_dir())
.await
.unwrap();
let args = CurrentArgs {
manifest_path: Some(manifest_path),
format: "github-actions".to_string(),
github_output: Some(output_file.path().to_string_lossy().to_string()),
};
assert!(current(args).await.is_ok());
let content = async_fs_io::read_string_bounded(output_file.path(), 1024 * 1024)
.await
.unwrap();
assert!(content.contains("version=2.0.0"));
}
#[tokio::test]
async fn test_current_invalid_format() {
let _dir = create_temp_cargo_project(
r#"
[package]
name = "test"
version = "1.0.0"
"#,
)
.await;
let manifest_path = _dir.path().join("Cargo.toml");
let args = CurrentArgs {
manifest_path: Some(manifest_path),
format: "invalid".to_string(),
github_output: None,
};
assert!(current(args).await.is_err());
}
#[tokio::test]
async fn test_current_file_not_found() {
let args = CurrentArgs {
manifest_path: Some("/nonexistent/Cargo.toml".into()),
format: "version".to_string(),
github_output: None,
};
assert!(current(args).await.is_err());
}
#[tokio::test]
async fn test_current_no_version() {
let _dir = create_temp_cargo_project(
r#"
[package]
name = "test"
"#,
)
.await;
let manifest_path = _dir.path().join("Cargo.toml");
let args = CurrentArgs {
manifest_path: Some(manifest_path),
format: "version".to_string(),
github_output: None,
};
let result = current(args).await;
assert!(result.is_ok());
}
}