Skip to main content

callisto_graph/
error.rs

1use std::path::PathBuf;
2
3use callisto_model::{GroupName, ManifestError, PackageId, TagTemplateError, VersionParseError};
4
5pub use crate::locate::LocateError;
6
7#[derive(Clone, Debug, thiserror::Error, miette::Diagnostic, PartialEq, Eq)]
8#[allow(clippy::result_large_err)]
9#[non_exhaustive]
10pub enum GraphError {
11    #[error(transparent)]
12    #[diagnostic(transparent)]
13    Locate(#[from] LocateError),
14
15    #[error(transparent)]
16    #[diagnostic(transparent)]
17    Manifest(#[from] ManifestError),
18
19    #[error(transparent)]
20    #[diagnostic(transparent)]
21    Config(#[from] ConfigError),
22
23    #[error(transparent)]
24    #[diagnostic(transparent)]
25    Format(#[from] callisto_format::ParseError),
26
27    #[error(transparent)]
28    #[diagnostic(transparent)]
29    Bump(#[from] callisto_format::BumpError),
30
31    #[error(transparent)]
32    #[diagnostic(transparent)]
33    Changelog(#[from] callisto_changelog::ChangelogError),
34
35    #[cfg(feature = "inference")]
36    #[error(transparent)]
37    Conventional(#[from] callisto_conventional::ConventionalError),
38
39    #[error(transparent)]
40    TagTemplate(#[from] callisto_model::TagTemplateError),
41
42    #[error(transparent)]
43    VersionParse(#[from] callisto_model::VersionParseError),
44
45    #[error(transparent)]
46    #[diagnostic(transparent)]
47    Model(#[from] callisto_model::ModelError),
48
49    #[error("vcs error: {0}")]
50    #[diagnostic(transparent)]
51    Vcs(#[from] callisto_vcs::VcsError),
52
53    #[error("command error: {0}")]
54    Command(#[from] callisto_model::CommandError),
55
56    #[error("package `{id}` is defined at multiple paths: {}", .paths.iter().map(|p| p.display().to_string()).collect::<Vec<_>>().join(", "))]
57    #[diagnostic(
58        code(E100),
59        help("Ensure package IDs are unique across workspace manifest paths.")
60    )]
61    DuplicatePackage { id: PackageId, paths: Vec<PathBuf> },
62
63    #[error("package at `{path}` declares conflicting identities: {}", .ids.iter().map(|i| i.display_name()).collect::<Vec<_>>().join(", "))]
64    #[diagnostic(code(E101), help("Align package name declarations in manifest files."))]
65    SplitIdentity { path: PathBuf, ids: Vec<PackageId> },
66
67    #[error("package `{id}` was not found in the workspace")]
68    #[diagnostic(
69        code(E102),
70        help("Verify package is included in workspace members in callisto.toml.")
71    )]
72    UnknownPackage { id: PackageId },
73
74    #[error("name `{name}` is ambiguous in this workspace; candidates: {}", .candidates.iter().map(|c| c.display_name()).collect::<Vec<_>>().join(", "))]
75    #[diagnostic(
76        code(E103),
77        help("Use fully-qualified package ID with ecosystem prefix (e.g. cargo:pkg).")
78    )]
79    AmbiguousName {
80        name: String,
81        candidates: Vec<PackageId>,
82    },
83
84    #[error("dependency cycle detected: {}", .cycle.iter().map(|i| i.display_name()).collect::<Vec<_>>().join(" -> "))]
85    #[diagnostic(
86        code(E104),
87        help("Refactor workspace dependencies to break the cyclic dependency chain.")
88    )]
89    Cycle { cycle: Vec<PackageId> },
90
91    #[error("cascade failed to converge after {iterations} iterations")]
92    #[diagnostic(
93        code(E105),
94        help("Check for oscillating peer or linked group dependencies.")
95    )]
96    CascadeNotConverged { iterations: usize },
97
98    #[error("fixed group `{group}` members have divergent on-disk versions: {}", .members.iter().map(|(id, v)| format!("{}={}", id.display_name(), v.render())).collect::<Vec<_>>().join(", "))]
99    #[diagnostic(
100        code(E106),
101        help("Align on-disk versions for all members of the fixed group.")
102    )]
103    FixedGroupDivergent {
104        group: GroupName,
105        members: Vec<(PackageId, callisto_model::Version)>,
106    },
107
108    #[error("group `{group}` members use incompatible versioning grammars: {}", .members.iter().map(|(id, v)| format!("{}={:?}", id.display_name(), v.grammar())).collect::<Vec<_>>().join(", "))]
109    #[diagnostic(code(E107))]
110    GroupGrammarMismatch {
111        group: GroupName,
112        members: Vec<(PackageId, callisto_model::Version)>,
113    },
114
115    #[error("group `{group}` lists member `{member}`, which was not found in the workspace")]
116    #[diagnostic(code(E108))]
117    MissingGroupMember { group: GroupName, member: String },
118
119    #[error("package `{package}` is listed in multiple conflicting groups: {}", .groups.iter().map(|g| g.as_str()).collect::<Vec<_>>().join(", "))]
120    #[diagnostic(code(E109))]
121    ConflictingGroupMembership {
122        package: PackageId,
123        groups: Vec<GroupName>,
124    },
125
126    #[error(
127        "version dependency edge from `{from}` to `{to}` involves incompatible grammars: {source}"
128    )]
129    GrammarMismatch {
130        from: PackageId,
131        to: PackageId,
132        #[source]
133        source: callisto_model::GrammarMismatch,
134    },
135
136    #[error("on-disk versions changed since plan was generated for `{package}`: expected {}, found {}", .expected.render(), .found.render())]
137    OnDiskVersionDrift {
138        package: PackageId,
139        expected: callisto_model::Version,
140        found: callisto_model::Version,
141    },
142
143    #[error("workspace root `{root_manifest}` has conflicting version updates: {details}")]
144    WorkspaceVersionConflict {
145        root_manifest: PathBuf,
146        details: String,
147    },
148}
149
150#[derive(Clone, Debug, thiserror::Error, miette::Diagnostic, PartialEq, Eq)]
151#[non_exhaustive]
152pub enum ConfigError {
153    #[error("failed to read `{path}`: {message}")]
154    #[diagnostic(code(E110))]
155    Read { path: PathBuf, message: String },
156
157    #[error("`{path}` is not valid TOML: {message}")]
158    #[diagnostic(code(E111), help("Verify callisto.toml TOML syntax formatting."))]
159    ParseToml { path: PathBuf, message: String },
160
161    #[error("`{path}` is not valid YAML: {message}")]
162    #[diagnostic(code(E112))]
163    ParseYaml { path: PathBuf, message: String },
164
165    #[error("[[package-set]] `{pattern}` matched no packages")]
166    PackageSetMatchedNothing { pattern: String },
167
168    #[error("[[package]] `{pattern}` matched no package")]
169    PackageMatchedNothing { pattern: String },
170
171    #[error("package `{package}` is claimed by more than one [[package-set]]: {}", .patterns.join(", "))]
172    OverlappingPackageSets {
173        package: String,
174        patterns: Vec<String>,
175    },
176
177    #[error("group `{group}` and group `{other}` both list `{member}`")]
178    ConflictingGroupNames {
179        group: GroupName,
180        other: GroupName,
181        member: String,
182    },
183
184    #[error("group `{group}` has no members")]
185    EmptyGroup { group: GroupName },
186
187    #[error("duplicate group name `{group}`")]
188    DuplicateGroupName { group: GroupName },
189
190    #[error("`publish-to` names registry key `{key}`, which no [registries.*] block defines")]
191    UnknownRegistry { key: String },
192
193    #[error("`{path}` sets unknown callisto key `{key}`")]
194    UnknownKey { path: PathBuf, key: String },
195
196    #[error("`cascade.bump-severity` is `{found}`; expected `patch` or `minor`")]
197    InvalidBumpSeverity { found: String },
198
199    #[error("`pre-major-inference` is `{found}`; expected `off`, `conservative`, or `conservative-feat`")]
200    InvalidPreMajorInference { found: String },
201
202    #[error(transparent)]
203    Tag(#[from] TagTemplateError),
204
205    #[error(transparent)]
206    VersionParse(#[from] VersionParseError),
207}