Compare commits

...

2 commits

Author SHA1 Message Date
97a575316e Issues: skip & warn about any Issue that fails to parse
This lets us at least handle the other, valid issues, while informing
the user about the ones we don't understand.
2025-07-19 09:55:32 -06:00
2ba13ebaeb Issue: get rid of all unwraps
Make and return errors instead.
2025-07-19 09:55:32 -06:00
2 changed files with 40 additions and 14 deletions

View file

@ -153,9 +153,9 @@ impl Issue {
} }
} }
if description == None { let Some(description) = description else {
return Err(IssueError::IssueParseError); return Err(IssueError::IssueParseError);
} };
// parse the issue ID from the directory name // parse the issue ID from the directory name
let id = if let Some(parsed_id) = match dir.file_name() { let id = if let Some(parsed_id) = match dir.file_name() {
@ -179,7 +179,7 @@ impl Issue {
state: state, state: state,
dependencies, dependencies,
assignee, assignee,
description: description.unwrap(), description,
comments, comments,
dir: std::path::PathBuf::from(dir), dir: std::path::PathBuf::from(dir),
}) })
@ -267,9 +267,9 @@ impl Issue {
"edit description of issue {}", "edit description of issue {}",
description_filename description_filename
.parent() .parent()
.unwrap() .ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?
.file_name() .file_name()
.unwrap() .ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?
.to_string_lossy(), .to_string_lossy(),
))?; ))?;
Ok(()) Ok(())
@ -293,7 +293,10 @@ impl Issue {
write!(state_file, "{}", new_state)?; write!(state_file, "{}", new_state)?;
self.commit(&format!( self.commit(&format!(
"change state of issue {}, {} -> {}", "change state of issue {}, {} -> {}",
self.dir.file_name().unwrap().to_string_lossy(), self.dir
.file_name()
.ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?
.to_string_lossy(),
old_state, old_state,
new_state, new_state,
))?; ))?;
@ -323,7 +326,10 @@ impl Issue {
self.done_time = Some(done_time.clone()); self.done_time = Some(done_time.clone());
self.commit(&format!( self.commit(&format!(
"set done-time of issue {} to {}", "set done-time of issue {} to {}",
self.dir.file_name().unwrap().to_string_lossy(), self.dir
.file_name()
.ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?
.to_string_lossy(),
done_time, done_time,
))?; ))?;
Ok(()) Ok(())
@ -341,7 +347,10 @@ impl Issue {
write!(assignee_file, "{}", new_assignee)?; write!(assignee_file, "{}", new_assignee)?;
self.commit(&format!( self.commit(&format!(
"change assignee of issue {}, {} -> {}", "change assignee of issue {}, {} -> {}",
self.dir.file_name().unwrap().to_string_lossy(), self.dir
.file_name()
.ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?
.to_string_lossy(),
old_assignee, old_assignee,
new_assignee, new_assignee,
))?; ))?;
@ -358,7 +367,10 @@ impl Issue {
self.tags.sort(); self.tags.sort();
self.commit_tags(&format!( self.commit_tags(&format!(
"issue {} add tag {}", "issue {} add tag {}",
self.dir.file_name().unwrap().to_string_lossy(), self.dir
.file_name()
.ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?
.to_string_lossy(),
tag tag
))?; ))?;
Ok(()) Ok(())
@ -373,7 +385,10 @@ impl Issue {
self.tags.remove(index); self.tags.remove(index);
self.commit_tags(&format!( self.commit_tags(&format!(
"issue {} remove tag {}", "issue {} remove tag {}",
self.dir.file_name().unwrap().to_string_lossy(), self.dir
.file_name()
.ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?
.to_string_lossy(),
tag tag
))?; ))?;
Ok(()) Ok(())
@ -432,8 +447,8 @@ impl Issue {
.spawn()? .spawn()?
.wait_with_output()?; .wait_with_output()?;
if !result.status.success() { if !result.status.success() {
println!("stdout: {}", std::str::from_utf8(&result.stdout).unwrap()); println!("stdout: {}", &String::from_utf8_lossy(&result.stdout));
println!("stderr: {}", std::str::from_utf8(&result.stderr).unwrap()); println!("stderr: {}", &String::from_utf8_lossy(&result.stderr));
return Err(IssueError::EditorError); return Err(IssueError::EditorError);
} }
if !description_filename.exists() || description_filename.metadata()?.len() == 0 { if !description_filename.exists() || description_filename.metadata()?.len() == 0 {

View file

@ -56,8 +56,19 @@ impl Issues {
for direntry in dir.read_dir()? { for direntry in dir.read_dir()? {
if let Ok(direntry) = direntry { if let Ok(direntry) = direntry {
if direntry.metadata()?.is_dir() { if direntry.metadata()?.is_dir() {
let issue = crate::issue::Issue::new_from_dir(direntry.path().as_path())?; match crate::issue::Issue::new_from_dir(direntry.path().as_path()) {
issues.add_issue(issue); Err(e) => {
println!(
"failed to parse issue {}, skipping",
direntry.file_name().to_string_lossy()
);
println!("ignoring error: {:?}", e);
continue;
}
Ok(issue) => {
issues.add_issue(issue);
}
}
} else if direntry.file_name() == "config.toml" { } else if direntry.file_name() == "config.toml" {
issues.parse_config(direntry.path().as_path())?; issues.parse_config(direntry.path().as_path())?;
} else { } else {