Skip to main content

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}