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}