stackless_stripe_projects/
error.rs1use stackless_core::fault::{ErrorContext, Fault, codes};
4
5#[derive(Debug, thiserror::Error)]
6pub enum ProjectsError {
7 #[error("the Stripe CLI or its `projects` plugin is unavailable: {detail}")]
8 Unavailable { detail: String },
9
10 #[error("Stripe Projects is not authenticated: {detail}")]
11 Auth { detail: String },
12
13 #[error("`stripe projects {command}` failed: {detail}")]
14 Failed { command: String, detail: String },
15
16 #[error(
17 "another stackless process holds the Stripe Projects lock for {definition_dir}: {detail}"
18 )]
19 LockHeld {
20 definition_dir: String,
21 detail: String,
22 },
23
24 #[error("cannot anchor the stack's Stripe project: {detail}")]
25 ProjectAnchor { detail: String },
26
27 #[error("provisioning {resource:?} via Stripe Projects did not complete: {detail}")]
28 ProvisionFailed { resource: String, detail: String },
29
30 #[error("the Stripe Projects catalog has no service {reference:?}")]
31 CatalogMissing { reference: String },
32
33 #[error("config for {reference:?} does not match the Stripe Projects catalog: {}", violations.join("; "))]
34 ConfigSchema {
35 reference: &'static str,
36 violations: Vec<String>,
37 },
38}
39
40impl Fault for ProjectsError {
41 fn code(&self) -> &'static str {
42 match self {
43 Self::Unavailable { .. } => codes::STRIPE_PROJECTS_UNAVAILABLE,
44 Self::Auth { .. } => codes::STRIPE_PROJECTS_AUTH,
45 Self::Failed { .. } => codes::STRIPE_PROJECTS_FAILED,
46 Self::LockHeld { .. } => codes::STRIPE_PROJECTS_LOCK_HELD,
47 Self::ProjectAnchor { .. } => codes::STRIPE_PROJECT_ANCHOR,
48 Self::ProvisionFailed { .. } => codes::STRIPE_PROJECTS_PROVISION_FAILED,
49 Self::CatalogMissing { .. } => codes::STRIPE_PROJECTS_CATALOG_MISSING,
50 Self::ConfigSchema { .. } => codes::STRIPE_PROJECTS_CONFIG_SCHEMA,
51 }
52 }
53
54 fn remediation(&self) -> String {
55 match self {
56 Self::Unavailable { .. } => {
57 "install the Stripe CLI (https://docs.stripe.com/stripe-cli), then run \
58 `stripe plugin install projects`"
59 .into()
60 }
61 Self::Auth { .. } => "run `stripe login`, then re-run `up`".into(),
62 Self::Failed { command, .. } => {
63 format!(
64 "run `stackless doctor` to see aggregated preflight blockers, or \
65 `stripe projects {command}` by hand, then re-run"
66 )
67 }
68 Self::LockHeld { .. } => {
69 "another `stackless up` is provisioning Stripe Projects in this definition dir; \
70 wait for it to finish, then re-run `up`"
71 .into()
72 }
73 Self::ProjectAnchor { .. } => {
74 "ensure the definition dir is writable and `stripe projects status` reports a \
75 linked project, then re-run `up`"
76 .into()
77 }
78 Self::ProvisionFailed { .. } => {
79 "wait a minute for the provider to finish provisioning and re-run `up` to resume"
80 .into()
81 }
82 Self::CatalogMissing { reference } => {
83 let provider = reference
84 .split_once('/')
85 .map(|(p, _)| p)
86 .unwrap_or(reference);
87 format!(
88 "run `stripe projects catalog {provider} --json`; the filter token may not \
89 match this provider, or the service may have been renamed or removed"
90 )
91 }
92 Self::ConfigSchema { .. } => {
93 "the service's catalog `configuration_schema` changed; update the plugin's typed \
94 config to match (the catalog gap test pins this)"
95 .into()
96 }
97 }
98 }
99
100 fn context(&self) -> ErrorContext {
101 ErrorContext::default()
102 }
103}