use anyhow::Result;
use clap::Parser;
use crate::atlassian::adf_validated::ValidatedAdfDocument;
use crate::atlassian::confluence_api::ConfluenceApi;
use crate::cli::atlassian::format::ContentFormat;
use crate::cli::atlassian::helpers::{create_client, prepare_write, run_write};
#[derive(Parser)]
pub struct WriteCommand {
pub id: String,
pub file: Option<String>,
#[arg(long, value_enum, default_value_t = ContentFormat::Jfm)]
pub format: ContentFormat,
#[arg(long)]
pub force: bool,
#[arg(long)]
pub dry_run: bool,
}
impl WriteCommand {
pub async fn execute(self) -> Result<()> {
let (adf, title, source) = prepare_write(self.file.as_deref(), &self.format)?;
if self.dry_run {
return crate::cli::atlassian::helpers::print_dry_run(
&self.id,
&adf,
&title,
source.as_deref(),
);
}
let validated = ValidatedAdfDocument::try_new_with_source(adf, source.as_deref())?;
let (client, _instance_url) = create_client()?;
let api = ConfluenceApi::new(client);
run_write(&self.id, &validated, &title, self.force, &api).await
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
use std::fs;
#[test]
fn write_command_struct_fields() {
let cmd = WriteCommand {
id: "12345".to_string(),
file: Some("page.md".to_string()),
format: ContentFormat::Jfm,
force: false,
dry_run: true,
};
assert_eq!(cmd.id, "12345");
assert!(!cmd.force);
assert!(cmd.dry_run);
}
#[test]
fn dry_run_adf_format() {
let temp_dir = tempfile::tempdir().unwrap();
let file_path = temp_dir.path().join("page.json");
let adf_json = r#"{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Hello"}]}]}"#;
fs::write(&file_path, adf_json).unwrap();
let cmd = WriteCommand {
id: "12345".to_string(),
file: Some(file_path.to_str().unwrap().to_string()),
format: ContentFormat::Adf,
force: false,
dry_run: true,
};
let rt = tokio::runtime::Runtime::new().unwrap();
let result = rt.block_on(cmd.execute());
assert!(result.is_ok());
}
#[test]
fn execute_send_path_rejects_invalid_adf_nesting() {
let temp_dir = tempfile::tempdir().unwrap();
let file_path = temp_dir.path().join("page.md");
let content = "---\ntype: confluence\ninstance: https://org.atlassian.net\npage_id: '12345'\ntitle: Bad\nspace_key: ENG\n---\n\n:::panel{type=info}\n:::expand{title=\"x\"}\nbody\n:::\n:::\n";
fs::write(&file_path, content).unwrap();
let cmd = WriteCommand {
id: "12345".to_string(),
file: Some(file_path.to_str().unwrap().to_string()),
format: ContentFormat::Jfm,
force: true,
dry_run: false,
};
let rt = tokio::runtime::Runtime::new().unwrap();
let err = rt.block_on(cmd.execute()).unwrap_err();
let msg = err.to_string();
assert!(msg.contains("invalid ADF nesting"));
assert!(msg.contains("`expand` cannot be a child of `panel`"));
}
#[test]
fn dry_run_confluence_document() {
let temp_dir = tempfile::tempdir().unwrap();
let file_path = temp_dir.path().join("page.md");
let content = "---\ntype: confluence\ninstance: https://org.atlassian.net\npage_id: '12345'\ntitle: My Page\nspace_key: ENG\n---\n\nPage body\n";
fs::write(&file_path, content).unwrap();
let cmd = WriteCommand {
id: "12345".to_string(),
file: Some(file_path.to_str().unwrap().to_string()),
format: ContentFormat::Jfm,
force: false,
dry_run: true,
};
let rt = tokio::runtime::Runtime::new().unwrap();
let result = rt.block_on(cmd.execute());
assert!(result.is_ok());
}
}