use super::action::identity::ActionId;
use super::action::resolved::ResolvedAction;
use super::action::spec::Spec;
use super::action::specifier::Specifier;
use super::lock::LockEntry;
use super::manifest::overrides::ActionOverride;
use std::path::PathBuf;
#[derive(Debug, Default)]
#[expect(
clippy::module_name_repetitions,
reason = "ManifestDiff is clearer than Manifest when imported"
)]
pub struct ManifestDiff {
pub added: Vec<(ActionId, Specifier)>,
pub removed: Vec<ActionId>,
pub updated: Vec<(ActionId, Specifier)>,
pub overrides_added: Vec<(ActionId, ActionOverride)>,
pub overrides_removed: Vec<(ActionId, Vec<ActionOverride>)>,
}
impl ManifestDiff {
#[must_use]
pub fn is_empty(&self) -> bool {
self.added.is_empty()
&& self.removed.is_empty()
&& self.updated.is_empty()
&& self.overrides_added.is_empty()
&& self.overrides_removed.is_empty()
}
}
#[derive(Debug)]
pub struct LockEntryPatch {
pub version: Option<Option<String>>,
pub comment: Option<String>,
}
#[derive(Debug, Default)]
#[expect(
clippy::module_name_repetitions,
reason = "LockDiff is clearer than Lock when imported"
)]
pub struct LockDiff {
pub added: Vec<(Spec, LockEntry)>,
pub removed: Vec<Spec>,
pub updated: Vec<(Spec, LockEntryPatch)>,
}
impl LockDiff {
#[must_use]
pub fn is_empty(&self) -> bool {
self.added.is_empty() && self.removed.is_empty() && self.updated.is_empty()
}
}
#[derive(Debug)]
pub struct WorkflowPatch {
pub path: PathBuf,
pub pins: Vec<ResolvedAction>,
}
#[cfg(test)]
mod tests {
use super::{LockDiff, LockEntry, ManifestDiff};
use crate::domain::action::identity::{ActionId, CommitDate, CommitSha, Repository, Version};
use crate::domain::action::resolved::{Commit, ResolvedRef};
use crate::domain::action::spec::Spec;
use crate::domain::action::specifier::Specifier;
use crate::domain::action::uses_ref::RefType;
#[test]
fn manifest_diff_is_empty_when_default() {
let diff = ManifestDiff::default();
assert!(diff.is_empty());
}
#[test]
fn manifest_diff_is_not_empty_after_adding_entry() {
let diff = ManifestDiff {
added: vec![(ActionId::from("actions/checkout"), Specifier::parse("^4"))],
..Default::default()
};
assert!(!diff.is_empty());
}
#[test]
fn lock_diff_is_empty_when_default() {
let diff = LockDiff::default();
assert!(diff.is_empty());
}
#[test]
fn lock_diff_is_not_empty_after_adding_entry() {
let diff = LockDiff {
added: vec![(
Spec::new(ActionId::from("actions/checkout"), Specifier::parse("^4")),
LockEntry {
reference: ResolvedRef::Tag(Version::from("v4")),
commit: Commit {
sha: CommitSha::from("abc123"),
repository: Repository::from("actions/checkout"),
ref_type: Some(RefType::Tag),
date: CommitDate::from("2026-01-01T00:00:00Z"),
},
},
)],
..Default::default()
};
assert!(!diff.is_empty());
}
}