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