Skip to main content

chronicle/
export.rs

1use std::io::Write;
2
3use crate::error::chronicle_error::GitSnafu;
4use crate::error::Result;
5use crate::git::GitOps;
6use serde::{Deserialize, Serialize};
7use snafu::ResultExt;
8
9/// A single export entry: commit SHA + timestamp + raw annotation JSON.
10///
11/// The annotation field is `serde_json::Value` so we can export both v1 and v2
12/// annotations without needing to know the schema version.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ExportEntry {
15    pub commit_sha: String,
16    pub timestamp: String,
17    pub annotation: serde_json::Value,
18}
19
20/// Export annotations as JSONL to a writer.
21///
22/// Iterates all notes under `refs/notes/chronicle`, and writes one JSON object
23/// per line. Preserves the raw annotation format (v1 or v2).
24pub fn export_annotations<W: Write>(git_ops: &dyn GitOps, writer: &mut W) -> Result<usize> {
25    let note_list = git_ops.list_annotated_commits(u32::MAX).context(GitSnafu)?;
26    let mut count = 0;
27
28    for sha in &note_list {
29        let note_content = match git_ops.note_read(sha).context(GitSnafu)? {
30            Some(content) => content,
31            None => continue,
32        };
33
34        let annotation: serde_json::Value = match serde_json::from_str(&note_content) {
35            Ok(a) => a,
36            Err(_) => continue, // skip malformed notes
37        };
38
39        let timestamp = annotation
40            .get("timestamp")
41            .and_then(|t| t.as_str())
42            .unwrap_or("")
43            .to_string();
44
45        let entry = ExportEntry {
46            commit_sha: sha.clone(),
47            timestamp,
48            annotation,
49        };
50
51        let line =
52            serde_json::to_string(&entry).map_err(|e| crate::error::ChronicleError::Json {
53                source: e,
54                location: snafu::Location::default(),
55            })?;
56
57        writeln!(writer, "{line}").map_err(|e| crate::error::ChronicleError::Io {
58            source: e,
59            location: snafu::Location::default(),
60        })?;
61
62        count += 1;
63    }
64
65    Ok(count)
66}