use std::path::PathBuf;
use thiserror::Error;
pub type ChangelogResult<T> = Result<T, ChangelogError>;
#[derive(Debug, Error, Clone)]
pub enum ChangelogError {
#[error("Changelog file not found: {path}")]
NotFound {
path: PathBuf,
},
#[error("Failed to parse changelog at line {line}: {reason}")]
ParseError {
line: usize,
reason: String,
},
#[error("Invalid changelog format: expected {expected}, found {actual}")]
InvalidFormat {
expected: String,
actual: String,
},
#[error("Failed to generate changelog for version '{version}': {reason}")]
GenerationFailed {
version: String,
reason: String,
},
#[error("Failed to parse conventional commit '{commit}': {reason}")]
ConventionalCommitParseError {
commit: String,
reason: String,
},
#[error("Git operation failed: {operation} - {reason}")]
GitError {
operation: String,
reason: String,
},
#[error("Version not found in git history: {reason}")]
VersionNotFound {
reason: String,
},
#[error("Invalid version '{version}': {reason}")]
InvalidVersion {
version: String,
reason: String,
},
#[error("Failed to parse version from tag '{tag}': {reason}")]
VersionTagParseError {
tag: String,
reason: String,
},
#[error("Filesystem error at '{path}': {reason}")]
FileSystemError {
path: PathBuf,
reason: String,
},
#[error("Invalid changelog path '{path}': {reason}")]
InvalidPath {
path: PathBuf,
reason: String,
},
#[error("Template rendering failed: {reason}")]
TemplateError {
reason: String,
},
#[error("Empty changelog for version '{version}': no commits to include")]
EmptyChangelog {
version: String,
},
#[error("Invalid changelog configuration: {reason}")]
InvalidConfig {
reason: String,
},
#[error("Package '{package}' not found in workspace")]
PackageNotFound {
package: String,
},
#[error("Failed to merge changelog sections: {reason}")]
MergeError {
reason: String,
},
#[error("Invalid commit range for changelog: {reason}")]
InvalidCommitRange {
reason: String,
},
#[error("Failed to extract references from commit message: {reason}")]
ReferenceExtractionError {
reason: String,
},
#[error("Repository URL not configured: cannot generate {link_type} links")]
RepositoryUrlMissing {
link_type: String,
},
#[error("Failed to update changelog at '{path}': {reason}")]
UpdateFailed {
path: PathBuf,
reason: String,
},
#[error("Unsupported changelog format: {format}")]
UnsupportedFormat {
format: String,
},
#[error("Failed to detect breaking changes: {reason}")]
BreakingChangeDetectionError {
reason: String,
},
#[error("Changelog already exists for version '{version}' in '{path}'")]
ChangelogExists {
version: String,
path: PathBuf,
},
}
impl AsRef<str> for ChangelogError {
fn as_ref(&self) -> &str {
match self {
Self::NotFound { .. } => "changelog not found",
Self::ParseError { .. } => "changelog parse error",
Self::InvalidFormat { .. } => "invalid changelog format",
Self::GenerationFailed { .. } => "changelog generation failed",
Self::ConventionalCommitParseError { .. } => "conventional commit parse error",
Self::GitError { .. } => "git error",
Self::VersionNotFound { .. } => "version not found",
Self::InvalidVersion { .. } => "invalid version",
Self::VersionTagParseError { .. } => "version tag parse error",
Self::FileSystemError { .. } => "filesystem error",
Self::InvalidPath { .. } => "invalid path",
Self::TemplateError { .. } => "template error",
Self::EmptyChangelog { .. } => "empty changelog",
Self::InvalidConfig { .. } => "invalid configuration",
Self::PackageNotFound { .. } => "package not found",
Self::MergeError { .. } => "merge error",
Self::InvalidCommitRange { .. } => "invalid commit range",
Self::ReferenceExtractionError { .. } => "reference extraction error",
Self::RepositoryUrlMissing { .. } => "repository url missing",
Self::UpdateFailed { .. } => "update failed",
Self::UnsupportedFormat { .. } => "unsupported format",
Self::BreakingChangeDetectionError { .. } => "breaking change detection error",
Self::ChangelogExists { .. } => "changelog exists",
}
}
}
impl ChangelogError {
#[must_use]
pub fn is_transient(&self) -> bool {
matches!(
self,
Self::FileSystemError { .. } | Self::GitError { .. } | Self::UpdateFailed { .. }
)
}
#[must_use]
pub fn is_git_related(&self) -> bool {
matches!(
self,
Self::GitError { .. }
| Self::VersionNotFound { .. }
| Self::VersionTagParseError { .. }
| Self::InvalidCommitRange { .. }
)
}
#[must_use]
pub fn is_parse_related(&self) -> bool {
matches!(
self,
Self::ParseError { .. }
| Self::ConventionalCommitParseError { .. }
| Self::VersionTagParseError { .. }
| Self::InvalidFormat { .. }
)
}
}