changeset_operations/traits/changeset_io.rs
1//! Changeset I/O traits for reading and writing changeset files.
2//!
3//! # Consumed Changeset Lifecycle
4//!
5//! Changesets follow a specific lifecycle during the prerelease workflow:
6//!
7//! 1. **Creation**: A changeset file is created via `cargo changeset add` with no
8//! `consumedForPrerelease` field.
9//!
10//! 2. **Consumption**: When a prerelease is created (`cargo changeset release --prerelease`),
11//! changesets are marked as consumed by setting `consumedForPrerelease` to the prerelease
12//! version string (e.g., "1.0.1-alpha.1"). This prevents the same changes from being
13//! included in subsequent prereleases while preserving the changeset for the eventual
14//! stable release.
15//!
16//! 3. **Exclusion**: Consumed changesets are excluded from `list_changesets()` but included
17//! in `list_consumed_changesets()`. This ensures subsequent prereleases only process
18//! new changes.
19//!
20//! 4. **Aggregation**: When graduating from prerelease to stable, consumed changesets are
21//! loaded and aggregated into the final changelog entry alongside any new changesets.
22//! The `consumedForPrerelease` flag is cleared during graduation.
23//!
24//! 5. **Deletion**: After a stable release, all changeset files (both previously consumed
25//! and newly processed) are deleted, completing the lifecycle.
26
27use std::path::{Path, PathBuf};
28
29use changeset_core::Changeset;
30use semver::Version;
31
32use crate::Result;
33
34/// Reads changeset files from the filesystem.
35///
36/// See the [module-level documentation](self) for details on the consumed changeset lifecycle.
37pub trait ChangesetReader: Send + Sync {
38 /// # Errors
39 ///
40 /// Returns an error if the file cannot be read or parsed.
41 fn read_changeset(&self, path: &Path) -> Result<Changeset>;
42
43 /// # Errors
44 ///
45 /// Returns an error if the directory cannot be read.
46 fn list_changesets(&self, changeset_dir: &Path) -> Result<Vec<PathBuf>>;
47
48 /// # Errors
49 ///
50 /// Returns an error if the directory cannot be read.
51 fn list_consumed_changesets(&self, changeset_dir: &Path) -> Result<Vec<PathBuf>>;
52}
53
54pub trait ChangesetWriter: Send + Sync {
55 /// # Errors
56 ///
57 /// Returns an error if the changeset cannot be serialized or written.
58 fn write_changeset(&self, changeset_dir: &Path, changeset: &Changeset) -> Result<String>;
59
60 /// Writes a changeset to a specific file path.
61 ///
62 /// Unlike `write_changeset`, this method writes to the exact path specified
63 /// rather than generating a new unique filename. This is used for saga
64 /// compensation to restore deleted changeset files.
65 ///
66 /// # Errors
67 ///
68 /// Returns an error if the changeset cannot be serialized or written.
69 fn restore_changeset(&self, path: &Path, changeset: &Changeset) -> Result<()>;
70
71 #[must_use]
72 fn filename_exists(&self, changeset_dir: &Path, filename: &str) -> bool;
73
74 /// # Errors
75 ///
76 /// Returns an error if changesets cannot be read, parsed, or written.
77 fn mark_consumed_for_prerelease(
78 &self,
79 changeset_dir: &Path,
80 paths: &[&Path],
81 version: &Version,
82 ) -> Result<()>;
83
84 /// # Errors
85 ///
86 /// Returns an error if changesets cannot be read, parsed, or written.
87 fn clear_consumed_for_prerelease(&self, changeset_dir: &Path, paths: &[&Path]) -> Result<()>;
88}