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}