use serde_json::json;
use usage_rs::{Args, RunAsyncWith};
use yt::api::work_items::WorkItemChange;
use yt::output::Format;
use super::{day, duration, work_item_json, work_type};
use crate::cli::Ctx;
use crate::cli::issue::text;
#[derive(Args)]
#[usage(effect = "write")]
pub(crate) struct Log {
#[usage(arg, name = "ID")]
id: String,
#[usage(arg, name = "DURATION")]
duration: String,
#[usage(long, value_name = "DATE")]
date: Option<String>,
#[usage(long = "type", value_name = "TYPE")]
work_type: Option<String>,
#[usage(short, long, value_name = "TEXT")]
body: Option<String>,
#[usage(long, value_name = "PATH")]
body_file: Option<String>,
#[usage(long)]
dry_run: bool,
}
impl RunAsyncWith<&Ctx> for Log {
type Output = yt::Result<()>;
async fn run_async_with(self, ctx: &Ctx) -> Self::Output {
let duration = duration(&self.duration)?;
let date = day("--date", &self.date.clone().unwrap_or_else(yt::time::today))?;
let day_text = yt::time::date(date);
let text = text::main_text(self.body, self.body_file.as_deref())
.await?
.map(|text| text.trim_end().to_string())
.filter(|text| !text.is_empty());
let client = ctx.client().await?;
let id = client.instance().issue_id(&self.id)?;
let work_type = match &self.work_type {
Some(name) => Some(work_type(client, &id, name).await?),
None => None,
};
let change = WorkItemChange {
date: Some(date),
duration: Some(duration.clone()),
type_id: work_type.as_ref().map(|work_type| work_type.id.clone()),
text,
};
if self.dry_run {
if ctx.output.format() != Format::Table {
return ctx.output.json(&json!({
"issue": id,
"date": day_text,
"duration": duration,
"type": work_type.as_ref().map(|work_type| work_type.name.as_str()),
"text": change.text,
}));
}
let mut line = format!("{id}: log {duration} on {day_text}");
if let Some(work_type) = &work_type {
line.push_str(&format!(" ({})", work_type.name));
}
if let Some(text) = &change.text {
line.push_str(&format!(" \"{}\"", text.lines().next().unwrap_or("")));
}
return ctx.output.write(&line);
}
let item = yt::api::work_items::create(client, &id, &change).await?;
match ctx.output.format() {
Format::Table => {
ctx.note(&format!("Logged {} on {id}", item.presentation()));
Ok(())
}
Format::Json => ctx.output.json(&work_item_json(&item)),
Format::Ndjson => ctx.output.ndjson(&work_item_json(&item)),
}
}
}