use crate::commands::parse_selector;
use crate::error::Result;
use crate::model::Issue;
use crate::storage::Store;
pub fn run(store: &Store, raw: &str) -> Result<()> {
let issue = get(store, raw)?;
print!("{}", issue.to_file_contents());
Ok(())
}
pub fn get(store: &Store, raw: &str) -> Result<Issue> {
let selector = parse_selector(store, raw)?;
store.get(selector)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::{Issue, Priority, Status};
use std::fs;
use tempfile::TempDir;
fn make_store() -> (TempDir, Store) {
let tmp = TempDir::new().unwrap();
let dir = tmp.path().join("issues");
fs::create_dir_all(dir.join("alice")).unwrap();
let config_path = tmp.path().join("tix.toml");
let config = crate::config::Config {
issues_dir: dir.clone(),
..crate::config::Config::default()
};
config.save(&config_path).unwrap();
let config = crate::config::Config::load_with_warning(&config_path, |_| {}).unwrap();
(
tmp,
Store {
issues_dir: dir,
config,
},
)
}
fn seed(store: &Store, number: u32, title: &str) -> Issue {
let mut issue = Issue {
number,
title: title.to_string(),
status: Status::new("todo"),
labels: vec![],
priority: Priority::default(),
assignee: Some("alice".to_string()),
estimate: None,
commit: None,
gitlab_id: None,
linear_id: None,
mission: None,
task: None,
created: "2026-01-01".to_string(),
updated: "2026-01-01".to_string(),
filename: String::new(),
body: "the body".to_string(),
};
issue.filename = format!("alice/2026-01-01-{}.md", crate::slug::slugify(title));
fs::write(
store.issues_dir.join(&issue.filename),
issue.to_file_contents(),
)
.unwrap();
issue
}
#[test]
fn get_returns_the_full_record() {
let (tmp, store) = make_store();
let _ = tmp;
let seeded = seed(&store, 1, "Get me");
let issue = get(&store, &seeded.number.to_string()).unwrap();
assert_eq!(issue.title, "Get me");
assert_eq!(issue.body, "the body");
}
#[test]
fn get_selector_miss_is_not_found() {
let (tmp, store) = make_store();
let _ = tmp;
let err = get(&store, "999").unwrap_err();
assert!(
matches!(err, crate::error::TixError::NotFound(_)),
"missing issue must surface as NotFound, got {err}"
);
}
#[test]
fn get_ambiguous_selector_is_an_error() {
let (tmp, store) = make_store();
let _ = tmp;
seed(&store, 1, "Shared title");
seed(&store, 2, "Shared title other");
let err = get(&store, "Shared").unwrap_err();
assert!(
matches!(err, crate::error::TixError::InvalidInput(_)),
"ambiguous selector must be an InvalidInput error, got {err}"
);
}
}