diff --git a/src/bin/ent/main.rs b/src/bin/ent/main.rs index 5c794e5..b211383 100644 --- a/src/bin/ent/main.rs +++ b/src/bin/ent/main.rs @@ -84,12 +84,6 @@ enum Commands { #[arg(allow_hyphen_values = true)] tag: Option, }, - - // Set the `done_time` of the Issue. - DoneTime { - issue_id: String, - done_time: Option, - }, } fn handle_command( @@ -152,7 +146,7 @@ fn handle_command( these_uuids.sort_by(|a_id, b_id| { let a = issues.issues.get(*a_id).unwrap(); let b = issues.issues.get(*b_id).unwrap(); - a.creation_time.cmp(&b.creation_time) + a.timestamp.cmp(&b.timestamp) }); println!("{:?}:", state); for uuid in these_uuids { @@ -197,10 +191,8 @@ fn handle_command( } Commands::New { description } => { - let issues_database = entomologist::database::make_issues_database( - issues_database_source, - entomologist::database::IssuesDatabaseAccess::ReadWrite, - )?; + let issues_database = + entomologist::database::make_issues_database(issues_database_source, entomologist::database::IssuesDatabaseAccess::ReadWrite)?; match entomologist::issue::Issue::new(&issues_database.dir, description) { Err(entomologist::issue::IssueError::EmptyDescription) => { println!("no new issue created"); @@ -217,10 +209,8 @@ fn handle_command( } Commands::Edit { uuid } => { - let issues_database = entomologist::database::make_issues_database( - issues_database_source, - entomologist::database::IssuesDatabaseAccess::ReadWrite, - )?; + let issues_database = + entomologist::database::make_issues_database(issues_database_source, entomologist::database::IssuesDatabaseAccess::ReadWrite)?; let mut issues = entomologist::issues::Issues::new_from_dir(&issues_database.dir)?; if let Some(issue) = issues.get_mut_issue(uuid) { match issue.edit_description() { @@ -259,10 +249,7 @@ fn handle_command( Some(issue) => { println!("issue {}", issue_id); println!("author: {}", issue.author); - println!("creation_time: {}", issue.creation_time); - if let Some(done_time) = &issue.done_time { - println!("done_time: {}", done_time); - } + println!("timestamp: {}", issue.timestamp); println!("state: {:?}", issue.state); if let Some(dependencies) = &issue.dependencies { println!("dependencies: {:?}", dependencies); @@ -276,7 +263,7 @@ fn handle_command( println!(""); println!("comment: {}", comment.uuid); println!("author: {}", comment.author); - println!("creation_time: {}", comment.creation_time); + println!("timestamp: {}", comment.timestamp); println!(""); println!("{}", comment.description); } @@ -292,10 +279,8 @@ fn handle_command( new_state, } => match new_state { Some(new_state) => { - let issues_database = entomologist::database::make_issues_database( - issues_database_source, - entomologist::database::IssuesDatabaseAccess::ReadWrite, - )?; + let issues_database = + entomologist::database::make_issues_database(issues_database_source, entomologist::database::IssuesDatabaseAccess::ReadWrite)?; let mut issues = entomologist::issues::Issues::new_from_dir(&issues_database.dir)?; match issues.issues.get_mut(issue_id) { Some(issue) => { @@ -327,10 +312,8 @@ fn handle_command( issue_id, description, } => { - let issues_database = entomologist::database::make_issues_database( - issues_database_source, - entomologist::database::IssuesDatabaseAccess::ReadWrite, - )?; + let issues_database = + entomologist::database::make_issues_database(issues_database_source, entomologist::database::IssuesDatabaseAccess::ReadWrite)?; let mut issues = entomologist::issues::Issues::new_from_dir(&issues_database.dir)?; let Some(issue) = issues.get_mut_issue(issue_id) else { return Err(anyhow::anyhow!("issue {} not found", issue_id)); @@ -355,13 +338,9 @@ fn handle_command( } Commands::Sync { remote } => { - if let entomologist::database::IssuesDatabaseSource::Branch(branch) = - issues_database_source - { - let issues_database = entomologist::database::make_issues_database( - issues_database_source, - entomologist::database::IssuesDatabaseAccess::ReadWrite, - )?; + if let entomologist::database::IssuesDatabaseSource::Branch(branch) = issues_database_source { + let issues_database = + entomologist::database::make_issues_database(issues_database_source, entomologist::database::IssuesDatabaseAccess::ReadWrite)?; entomologist::git::sync(&issues_database.dir, remote, branch)?; println!("synced {:?} with {:?}", branch, remote); } else { @@ -448,38 +427,6 @@ fn handle_command( } } } - - Commands::DoneTime { - issue_id, - done_time, - } => { - let issues = entomologist::database::read_issues_database(issues_database_source)?; - let Some(issue) = issues.issues.get(issue_id) else { - return Err(anyhow::anyhow!("issue {} not found", issue_id)); - }; - match done_time { - Some(done_time) => { - // Add or remove tag. - let issues_database = entomologist::database::make_issues_database( - issues_database_source, - entomologist::database::IssuesDatabaseAccess::ReadWrite, - )?; - let mut issues = - entomologist::issues::Issues::new_from_dir(&issues_database.dir)?; - let Some(issue) = issues.get_mut_issue(issue_id) else { - return Err(anyhow::anyhow!("issue {} not found", issue_id)); - }; - let done_time = chrono::DateTime::parse_from_rfc3339(done_time) - .unwrap() - .with_timezone(&chrono::Local); - issue.set_done_time(done_time)?; - } - None => match &issue.done_time { - Some(done_time) => println!("done_time: {}", done_time), - None => println!("None"), - }, - }; - } } Ok(()) @@ -493,9 +440,7 @@ fn main() -> anyhow::Result<()> { // println!("{:?}", args); let issues_database_source = match (&args.issues_dir, &args.issues_branch) { - (Some(dir), None) => { - entomologist::database::IssuesDatabaseSource::Dir(std::path::Path::new(dir)) - } + (Some(dir), None) => entomologist::database::IssuesDatabaseSource::Dir(std::path::Path::new(dir)), (None, Some(branch)) => entomologist::database::IssuesDatabaseSource::Branch(branch), (None, None) => entomologist::database::IssuesDatabaseSource::Branch("entomologist-data"), (Some(_), Some(_)) => { diff --git a/src/comment.rs b/src/comment.rs index 216b34f..c8e26c9 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -4,7 +4,7 @@ use std::io::{IsTerminal, Write}; pub struct Comment { pub uuid: String, pub author: String, - pub creation_time: chrono::DateTime, + pub timestamp: chrono::DateTime, pub description: String, /// This is the directory that the comment lives in. Only used @@ -53,13 +53,13 @@ impl Comment { } let author = crate::git::git_log_oldest_author(comment_dir)?; - let creation_time = crate::git::git_log_oldest_timestamp(comment_dir)?; + let timestamp = crate::git::git_log_oldest_timestamp(comment_dir)?; let dir = std::path::PathBuf::from(comment_dir); Ok(Self { uuid: String::from(dir.file_name().unwrap().to_string_lossy()), author, - creation_time, + timestamp, description: description.unwrap(), dir: std::path::PathBuf::from(comment_dir), }) @@ -84,7 +84,7 @@ impl Comment { let mut comment = crate::comment::Comment { uuid, author: String::from(""), // this will be updated from git when we re-read this comment - creation_time: chrono::Local::now(), + timestamp: chrono::Local::now(), description: String::from(""), // this will be set immediately below dir: dir.clone(), }; @@ -204,7 +204,7 @@ mod tests { let expected = Comment { uuid: String::from("9055dac36045fe36545bed7ae7b49347"), author: String::from("Sebastian Kuzminsky "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-07T15:26:26-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-07T15:26:26-06:00") .unwrap() .with_timezone(&chrono::Local), description: String::from("This is a comment on issue dd79c8cfb8beeacd0460429944b4ecbe95a31561\n\nIt has multiple lines\n"), diff --git a/src/issue.rs b/src/issue.rs index bc3d959..0de413c 100644 --- a/src/issue.rs +++ b/src/issue.rs @@ -22,8 +22,7 @@ pub type IssueHandle = String; pub struct Issue { pub id: String, pub author: String, - pub creation_time: chrono::DateTime, - pub done_time: Option>, + pub timestamp: chrono::DateTime, pub tags: Vec, pub state: State, pub dependencies: Option>, @@ -44,8 +43,6 @@ pub enum IssueError { EnvVarError(#[from] std::env::VarError), #[error(transparent)] CommentError(#[from] crate::comment::CommentError), - #[error(transparent)] - ChronoParseError(#[from] chrono::format::ParseError), #[error("Failed to parse issue")] IssueParseError, #[error("Failed to parse state")] @@ -109,7 +106,6 @@ impl Issue { let mut comments = Vec::::new(); let mut assignee: Option = None; let mut tags = Vec::::new(); - let mut done_time: Option> = None; for direntry in dir.read_dir()? { if let Ok(direntry) = direntry { @@ -123,11 +119,6 @@ impl Issue { assignee = Some(String::from( std::fs::read_to_string(direntry.path())?.trim(), )); - } else if file_name == "done_time" { - let raw_done_time = chrono::DateTime::<_>::parse_from_rfc3339( - std::fs::read_to_string(direntry.path())?.trim(), - )?; - done_time = Some(raw_done_time.into()); } else if file_name == "dependencies" { let dep_strings = std::fs::read_to_string(direntry.path())?; let deps: Vec = dep_strings @@ -168,13 +159,12 @@ impl Issue { }; let author = crate::git::git_log_oldest_author(dir)?; - let creation_time = crate::git::git_log_oldest_timestamp(dir)?; + let timestamp = crate::git::git_log_oldest_timestamp(dir)?; Ok(Self { id, author, - creation_time, - done_time, + timestamp, tags, state: state, dependencies, @@ -195,7 +185,7 @@ impl Issue { comments.push(comment); } } - comments.sort_by(|a, b| a.creation_time.cmp(&b.creation_time)); + comments.sort_by(|a, b| a.timestamp.cmp(&b.timestamp)); Ok(()) } @@ -230,8 +220,7 @@ impl Issue { let mut issue = Self { id: String::from(&issue_id), author: String::from(""), - creation_time: chrono::Local::now(), - done_time: None, + timestamp: chrono::Local::now(), tags: Vec::::new(), state: State::New, dependencies: None, @@ -254,7 +243,8 @@ impl Issue { None => issue.edit_description_file()?, }; - issue.commit(&format!("create new issue {}", issue_id))?; + crate::git::add(&issue_dir)?; + crate::git::commit(&issue_dir, &format!("create new issue {}", issue_id))?; Ok(issue) } @@ -263,15 +253,21 @@ impl Issue { pub fn edit_description(&mut self) -> Result<(), IssueError> { self.edit_description_file()?; let description_filename = self.description_filename(); - self.commit(&format!( - "edit description of issue {}", - description_filename - .parent() - .unwrap() - .file_name() - .unwrap() - .to_string_lossy(), - ))?; + crate::git::add(&description_filename)?; + if crate::git::worktree_is_dirty(&self.dir.to_string_lossy())? { + crate::git::commit( + &description_filename.parent().unwrap(), + &format!( + "edit description of issue {}", + description_filename + .parent() + .unwrap() + .file_name() + .unwrap() + .to_string_lossy() + ), + )?; + } Ok(()) } @@ -283,22 +279,24 @@ impl Issue { } } - /// Change the State of the Issue. If the new state is `Done`, - /// set the Issue `done_time`. Commits. + /// Change the State of the Issue. pub fn set_state(&mut self, new_state: State) -> Result<(), IssueError> { let old_state = self.state.clone(); let mut state_filename = std::path::PathBuf::from(&self.dir); state_filename.push("state"); let mut state_file = std::fs::File::create(&state_filename)?; write!(state_file, "{}", new_state)?; - self.commit(&format!( - "change state of issue {}, {} -> {}", - self.dir.file_name().unwrap().to_string_lossy(), - old_state, - new_state, - ))?; - if new_state == State::Done { - self.set_done_time(chrono::Local::now())?; + crate::git::add(&state_filename)?; + if crate::git::worktree_is_dirty(&self.dir.to_string_lossy())? { + crate::git::commit( + &self.dir, + &format!( + "change state of issue {}, {} -> {}", + self.dir.file_name().unwrap().to_string_lossy(), + old_state, + new_state, + ), + )?; } Ok(()) } @@ -311,24 +309,6 @@ impl Issue { Ok(()) } - /// Set the `done_time` of the Issue. Commits. - pub fn set_done_time( - &mut self, - done_time: chrono::DateTime, - ) -> Result<(), IssueError> { - let mut done_time_filename = std::path::PathBuf::from(&self.dir); - done_time_filename.push("done_time"); - let mut done_time_file = std::fs::File::create(&done_time_filename)?; - write!(done_time_file, "{}", done_time.to_rfc3339())?; - self.done_time = Some(done_time.clone()); - self.commit(&format!( - "set done-time of issue {} to {}", - self.dir.file_name().unwrap().to_string_lossy(), - done_time, - ))?; - Ok(()) - } - /// Set the Assignee of an Issue. pub fn set_assignee(&mut self, new_assignee: &str) -> Result<(), IssueError> { let old_assignee = match &self.assignee { @@ -339,12 +319,18 @@ impl Issue { assignee_filename.push("assignee"); let mut assignee_file = std::fs::File::create(&assignee_filename)?; write!(assignee_file, "{}", new_assignee)?; - self.commit(&format!( - "change assignee of issue {}, {} -> {}", - self.dir.file_name().unwrap().to_string_lossy(), - old_assignee, - new_assignee, - ))?; + crate::git::add(&assignee_filename)?; + if crate::git::worktree_is_dirty(&self.dir.to_string_lossy())? { + crate::git::commit( + &self.dir, + &format!( + "change assignee of issue {}, {} -> {}", + self.dir.file_name().unwrap().to_string_lossy(), + old_assignee, + new_assignee, + ), + )?; + } Ok(()) } @@ -458,15 +444,7 @@ impl Issue { for tag in &self.tags { writeln!(tags_file, "{}", tag)?; } - self.commit(commit_message)?; - Ok(()) - } - - fn commit(&self, commit_message: &str) -> Result<(), IssueError> { - crate::git::add(&self.dir)?; - if !crate::git::worktree_is_dirty(&self.dir.to_string_lossy())? { - return Ok(()); - } + crate::git::add(&tags_filename)?; crate::git::commit(&self.dir, commit_message)?; Ok(()) } @@ -483,10 +461,9 @@ mod tests { let expected = Issue { id: String::from("3943fc5c173fdf41c0a22251593cd476d96e6c9f"), author: String::from("Sebastian Kuzminsky "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: None, tags: Vec::::from([ String::from("tag1"), String::from("TAG2"), @@ -511,10 +488,9 @@ mod tests { let expected = Issue { id: String::from("7792b063eef6d33e7da5dc1856750c149ba678c6"), author: String::from("Sebastian Kuzminsky "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: None, tags: Vec::::new(), state: State::InProgress, dependencies: None, diff --git a/src/issues.rs b/src/issues.rs index 709a79d..42e964d 100644 --- a/src/issues.rs +++ b/src/issues.rs @@ -90,10 +90,9 @@ mod tests { expected.add_issue(crate::issue::Issue { id: uuid, author: String::from("Sebastian Kuzminsky "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: None, tags: Vec::::new(), state: crate::issue::State::InProgress, dependencies: None, @@ -110,10 +109,9 @@ mod tests { crate::issue::Issue { id: uuid, author: String::from("Sebastian Kuzminsky "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T12:14:26-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: None, tags: Vec::::from([ String::from("tag1"), String::from("TAG2"), @@ -143,14 +141,9 @@ mod tests { expected.add_issue(crate::issue::Issue { id: uuid, author: String::from("Sebastian Kuzminsky "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-03T11:59:44-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T11:59:44-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: Some( - chrono::DateTime::parse_from_rfc3339("2025-07-15T15:15:15-06:00") - .unwrap() - .with_timezone(&chrono::Local), - ), tags: Vec::::new(), state: crate::issue::State::Done, dependencies: None, @@ -172,7 +165,7 @@ mod tests { crate::comment::Comment { uuid: comment_uuid, author: String::from("Sebastian Kuzminsky "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-07T15:26:26-06:00").unwrap().with_timezone(&chrono::Local), + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-07T15:26:26-06:00").unwrap().with_timezone(&chrono::Local), description: String::from("This is a comment on issue dd79c8cfb8beeacd0460429944b4ecbe95a31561\n\nIt has multiple lines\n"), dir: std::path::PathBuf::from(comment_dir), } @@ -181,10 +174,9 @@ mod tests { crate::issue::Issue { id: uuid, author: String::from("Sebastian Kuzminsky "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-03T11:59:44-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-03T11:59:44-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: None, tags: Vec::::new(), state: crate::issue::State::WontDo, dependencies: None, @@ -210,10 +202,9 @@ mod tests { expected.add_issue(crate::issue::Issue { id: uuid, author: String::from("sigil-03 "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: None, tags: Vec::::new(), state: crate::issue::State::Done, dependencies: None, @@ -230,10 +221,9 @@ mod tests { crate::issue::Issue { id: uuid, author: String::from("sigil-03 "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: None, tags: Vec::::new(), state: crate::issue::State::WontDo, dependencies: None, @@ -251,10 +241,9 @@ mod tests { crate::issue::Issue { id: uuid, author: String::from("sigil-03 "), - creation_time: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") + timestamp: chrono::DateTime::parse_from_rfc3339("2025-07-05T13:55:49-06:00") .unwrap() .with_timezone(&chrono::Local), - done_time: None, tags: Vec::::new(), state: crate::issue::State::WontDo, dependencies: Some(vec![ diff --git a/test/0001/3fa5bfd93317ad25772680071d5ac3259cd2384f/done_time b/test/0001/3fa5bfd93317ad25772680071d5ac3259cd2384f/done_time deleted file mode 100644 index d455c4d..0000000 --- a/test/0001/3fa5bfd93317ad25772680071d5ac3259cd2384f/done_time +++ /dev/null @@ -1 +0,0 @@ -2025-07-15T15:15:15-06:00