1use std::fmt;
2
3use crate::{TeamName, UserName};
4
5#[derive(Clone, Debug, Eq, PartialEq)]
7pub enum Limitation {
8 TeamNotInOrganization {
10 team: TeamName,
12 forge: &'static str,
14 },
15 TeamOrganizationPermission {
18 team: TeamName,
20 actual: String,
22 expected: String,
24 },
25 TeamInherited {
27 team: TeamName,
29 forge: &'static str,
31 },
32 TeamPermissionIsOrganizationWide {
34 team: TeamName,
36 actual: String,
38 expected: String,
40 forge: &'static str,
42 },
43 TeamRoleNeedsOrganization {
45 team: TeamName,
47 role: String,
49 },
50 CollaboratorRoleNeedsOrganization {
52 user: UserName,
54 role: String,
56 },
57 NotReported {
59 field: &'static str,
61 },
62 WrittenOnEveryApply {
64 field: &'static str,
66 },
67 Unavailable {
69 field: &'static str,
71 },
72 EnforcedByOwner {
74 field: &'static str,
76 },
77 Ignored {
79 field: &'static str,
81 switch: &'static str,
83 },
84 MirrorOnly,
86 ActionsUnavailable {
88 group: &'static str,
90 },
91 ActionsPrivateOnly {
93 group: &'static str,
95 },
96 SecurityUnreadable {
98 field: &'static str,
100 },
101 CustomPropertiesUnsupported,
103 EnvironmentRuleUnmanaged {
105 environment: String,
107 rule: String,
109 },
110 VariablesWithoutEnvironment {
112 environment: Option<String>,
114 },
115 WebhookKindLeftAlone {
117 id: u64,
119 kind: String,
121 },
122 WebhookSecretKept {
124 url: String,
126 },
127 RequiredReviewersDropped {
129 ruleset: String,
131 },
132 UnmanagedRuleType {
134 ruleset: String,
136 kind: String,
138 },
139 UnaddressableRule {
141 name: String,
143 },
144}
145
146impl fmt::Display for Limitation {
147 #[expect(clippy::too_many_lines, reason = "one arm per limitation")]
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 match self {
150 Self::TeamNotInOrganization { team, forge } => {
151 write!(f, "team {team} is not in the {forge} organization")
152 }
153 Self::TeamOrganizationPermission {
154 team,
155 actual,
156 expected,
157 } => write!(
158 f,
159 "team {team} cannot be assigned: its organization-wide permission is {actual}, \
160 expected {expected}"
161 ),
162 Self::TeamInherited { team, forge } => write!(
163 f,
164 "team {team} is inherited from an all-repositories {forge} team and cannot be \
165 removed here"
166 ),
167 Self::TeamPermissionIsOrganizationWide {
168 team,
169 actual,
170 expected,
171 forge,
172 } => write!(
173 f,
174 "team {team} has permission {actual} and {expected} is declared, but {forge} only \
175 changes team permissions organization-wide"
176 ),
177 Self::TeamRoleNeedsOrganization { team, role } => write!(
178 f,
179 "team {team} needs {role}, which only organization repositories have"
180 ),
181 Self::CollaboratorRoleNeedsOrganization { user, role } => write!(
182 f,
183 "collaborator {user} needs {role}, which only organization repositories have"
184 ),
185 Self::NotReported { field } => {
186 write!(f, "{field} is not reported for this repository")
187 }
188 Self::WrittenOnEveryApply { field } => write!(
189 f,
190 "{field} is not reported by Forgejo, so it is written on every apply"
191 ),
192 Self::Unavailable { field } => {
193 write!(f, "{field} is not available for this repository")
194 }
195 Self::EnforcedByOwner { field } => write!(f, "{field} is enforced by the owner"),
196 Self::Ignored { field, switch } => {
197 write!(f, "{field} is ignored while {switch} is false")
198 }
199 Self::MirrorOnly => {
200 f.write_str("mirror_interval and enable_prune only apply to a mirror")
201 }
202 Self::ActionsUnavailable { group } => {
203 write!(f, "actions {group} is unavailable for this repository")
204 }
205 Self::ActionsPrivateOnly { group } => {
206 write!(f, "actions {group} applies to private repositories only")
207 }
208 Self::SecurityUnreadable { field } => {
209 write!(f, "security: {field} cannot be read, so it is not managed")
210 }
211 Self::CustomPropertiesUnsupported => f.write_str(
212 "custom properties: the repository does not support them, so they are not managed",
213 ),
214 Self::EnvironmentRuleUnmanaged { environment, rule } => write!(
215 f,
216 "environment {environment}: the {rule} protection rule is not managed"
217 ),
218 Self::VariablesWithoutEnvironment { environment } => {
219 if let Some(environment) = environment {
220 write!(f, "environment {environment} ")?;
221 }
222 f.write_str(
223 "variables: the environment does not exist, so its variables are not managed",
224 )
225 }
226 Self::WebhookKindLeftAlone { id, kind } => {
227 write!(f, "webhook {id} is a {kind} hook and is left alone")
228 }
229 Self::WebhookSecretKept { url } => write!(
230 f,
231 "webhook {url}: the delivery settings were left unchanged because GitHub would \
232 clear the secret set by hand"
233 ),
234 Self::RequiredReviewersDropped { ruleset } => write!(
235 f,
236 "ruleset \"{ruleset}\" has required_reviewers in its pull_request rule, which an \
237 update drops"
238 ),
239 Self::UnmanagedRuleType { ruleset, kind } => {
240 write!(
241 f,
242 "ruleset \"{ruleset}\" contains unmanaged rule type \"{kind}\""
243 )
244 }
245 Self::UnaddressableRule { name } => write!(
246 f,
247 "live branch rule \"{name}\" cannot be addressed by the API routes, so it is left \
248 in place"
249 ),
250 }
251 }
252}