github_actions_models/dependabot/
v2.rs

1//! "v2" Dependabot models.
2//!
3//! Resources:
4//! * [Configuration options for the `dependabot.yml` file](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file)
5//! * [JSON Schema for Dependabot v2](https://json.schemastore.org/dependabot-2.0.json)
6
7use indexmap::{IndexMap, IndexSet};
8use serde::Deserialize;
9
10/// A `dependabot.yml` configuration file.
11#[derive(Deserialize, Debug)]
12#[serde(rename_all = "kebab-case")]
13pub struct Dependabot {
14    /// Invariant: `2`
15    pub version: u64,
16    #[serde(default)]
17    pub enable_beta_ecosystems: bool,
18    #[serde(default)]
19    pub registries: IndexMap<String, Registry>,
20    pub updates: Vec<Update>,
21}
22
23/// Different registries known to Dependabot.
24#[derive(Deserialize, Debug)]
25#[serde(rename_all = "kebab-case", tag = "type")]
26pub enum Registry {
27    ComposerRepository {
28        url: String,
29        username: Option<String>,
30        password: Option<String>,
31    },
32    DockerRegistry {
33        url: String,
34        username: Option<String>,
35        password: Option<String>,
36        #[serde(default)]
37        replaces_base: bool,
38    },
39    Git {
40        url: String,
41        username: Option<String>,
42        password: Option<String>,
43    },
44    HexOrganization {
45        organization: String,
46        key: Option<String>,
47    },
48    HexRepository {
49        repo: Option<String>,
50        url: String,
51        auth_key: Option<String>,
52        public_key_fingerprint: Option<String>,
53    },
54    MavenRepository {
55        url: String,
56        username: Option<String>,
57        password: Option<String>,
58    },
59    NpmRegistry {
60        url: String,
61        username: Option<String>,
62        password: Option<String>,
63        #[serde(default)]
64        replaces_base: bool,
65    },
66    NugetFeed {
67        url: String,
68        username: Option<String>,
69        password: Option<String>,
70    },
71    PythonIndex {
72        url: String,
73        username: Option<String>,
74        password: Option<String>,
75        #[serde(default)]
76        replaces_base: bool,
77    },
78    RubygemsServer {
79        url: String,
80        username: Option<String>,
81        password: Option<String>,
82        #[serde(default)]
83        replaces_base: bool,
84    },
85    TerraformRegistry {
86        url: String,
87        token: Option<String>,
88    },
89}
90
91/// Cooldown settings for Dependabot updates.
92#[derive(Deserialize, Debug)]
93#[serde(rename_all = "kebab-case")]
94pub struct Cooldown {
95    pub default_days: Option<u64>,
96    pub semver_major_days: Option<u64>,
97    pub semver_minor_days: Option<u64>,
98    pub semver_patch_days: Option<u64>,
99    #[serde(default)]
100    pub include: Vec<String>,
101    #[serde(default)]
102    pub exclude: Vec<String>,
103}
104
105/// A `directory` or `directories` field in a Dependabot `update` directive.
106#[derive(Deserialize, Debug, PartialEq)]
107#[serde(rename_all = "kebab-case")]
108pub enum Directories {
109    Directory(String),
110    Directories(Vec<String>),
111}
112
113/// A single `update` directive.
114#[derive(Deserialize, Debug)]
115#[serde(rename_all = "kebab-case")]
116pub struct Update {
117    #[serde(default)]
118    pub allow: Vec<Allow>,
119    #[serde(default)]
120    pub assignees: IndexSet<String>,
121    pub commit_message: Option<CommitMessage>,
122    pub cooldown: Option<Cooldown>,
123    #[serde(flatten)]
124    pub directories: Directories,
125    #[serde(default)]
126    pub groups: IndexMap<String, Group>,
127    #[serde(default)]
128    pub ignore: Vec<Ignore>,
129    #[serde(default)]
130    pub insecure_external_code_execution: AllowDeny,
131    /// Labels to apply to this update group's pull requests.
132    ///
133    /// The default label is `dependencies`.
134    #[serde(default = "default_labels")]
135    pub labels: IndexSet<String>,
136    pub milestone: Option<u64>,
137    /// The maximum number of pull requests to open at a time from this
138    /// update group.
139    ///
140    /// The default maximum is 5.
141    #[serde(default = "default_open_pull_requests_limit")]
142    pub open_pull_requests_limit: u64,
143    pub package_ecosystem: PackageEcosystem,
144    // TODO: pull-request-branch-name
145    #[serde(default)]
146    pub rebase_strategy: RebaseStrategy,
147    #[serde(default, deserialize_with = "crate::common::scalar_or_vector")]
148    pub registries: Vec<String>,
149    #[serde(default)]
150    pub reviewers: IndexSet<String>,
151    pub schedule: Schedule,
152    pub target_branch: Option<String>,
153    #[serde(default)]
154    pub vendor: bool,
155    pub versioning_strategy: Option<VersioningStrategy>,
156}
157
158#[inline]
159fn default_labels() -> IndexSet<String> {
160    IndexSet::from(["dependencies".to_string()])
161}
162
163#[inline]
164fn default_open_pull_requests_limit() -> u64 {
165    // https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#open-pull-requests-limit
166    5
167}
168
169/// Allow rules for Dependabot updates.
170#[derive(Deserialize, Debug)]
171#[serde(rename_all = "kebab-case")]
172pub struct Allow {
173    pub dependency_name: Option<String>,
174    pub dependency_type: Option<DependencyType>,
175}
176
177/// Dependency types in `allow` rules.
178#[derive(Deserialize, Debug)]
179#[serde(rename_all = "kebab-case")]
180pub enum DependencyType {
181    Direct,
182    Indirect,
183    All,
184    Production,
185    Development,
186}
187
188/// Commit message settings for Dependabot updates.
189#[derive(Deserialize, Debug)]
190#[serde(rename_all = "kebab-case")]
191pub struct CommitMessage {
192    pub prefix: Option<String>,
193    pub prefix_development: Option<String>,
194    /// Invariant: `"scope"`
195    pub include: Option<String>,
196}
197
198/// Group settings for batched updates.
199#[derive(Deserialize, Debug)]
200#[serde(rename_all = "kebab-case")]
201pub struct Group {
202    /// This can only be [`DependencyType::Development`] or
203    /// [`DependencyType::Production`].
204    pub dependency_type: Option<DependencyType>,
205    #[serde(default)]
206    pub patterns: IndexSet<String>,
207    #[serde(default)]
208    pub exclude_patterns: IndexSet<String>,
209    #[serde(default)]
210    pub update_types: IndexSet<UpdateType>,
211}
212
213/// Update types for grouping.
214#[derive(Deserialize, Debug, Hash, Eq, PartialEq)]
215#[serde(rename_all = "kebab-case")]
216pub enum UpdateType {
217    Major,
218    Minor,
219    Patch,
220}
221
222/// Dependency ignore settings for updates.
223#[derive(Deserialize, Debug)]
224#[serde(rename_all = "kebab-case")]
225pub struct Ignore {
226    pub dependency_name: Option<String>,
227    /// These are, inexplicably, not [`UpdateType`] variants.
228    /// Instead, they're strings like `"version-update:semver-{major,minor,patch}"`.
229    #[serde(default)]
230    pub update_types: IndexSet<String>,
231    #[serde(default)]
232    pub versions: IndexSet<String>,
233}
234
235/// An "allow"/"deny" toggle.
236#[derive(Deserialize, Debug, Default)]
237#[serde(rename_all = "kebab-case")]
238pub enum AllowDeny {
239    Allow,
240    #[default]
241    Deny,
242}
243
244/// Supported packaging ecosystems.
245#[derive(Deserialize, Debug, PartialEq)]
246#[serde(rename_all = "kebab-case")]
247pub enum PackageEcosystem {
248    Bundler,
249    Cargo,
250    Composer,
251    Docker,
252    Elm,
253    Gitsubmodule,
254    GithubActions,
255    Gomod,
256    Gradle,
257    Maven,
258    Mix,
259    Npm,
260    Nuget,
261    Pip,
262    Pub,
263    Swift,
264    Terraform,
265}
266
267/// Rebase strategies for Dependabot updates.
268#[derive(Deserialize, Debug, Default, PartialEq)]
269#[serde(rename_all = "kebab-case")]
270pub enum RebaseStrategy {
271    #[default]
272    Auto,
273    Disabled,
274}
275
276/// Scheduling settings for Dependabot updates.
277#[derive(Deserialize, Debug)]
278#[serde(rename_all = "kebab-case")]
279pub struct Schedule {
280    pub interval: Interval,
281    pub day: Option<Day>,
282    pub time: Option<String>,
283    pub timezone: Option<String>,
284}
285
286/// Schedule intervals.
287#[derive(Deserialize, Debug, PartialEq)]
288#[serde(rename_all = "kebab-case")]
289pub enum Interval {
290    Daily,
291    Weekly,
292    Monthly,
293}
294
295/// Days of the week.
296#[derive(Deserialize, Debug, PartialEq)]
297#[serde(rename_all = "kebab-case")]
298pub enum Day {
299    Monday,
300    Tuesday,
301    Wednesday,
302    Thursday,
303    Friday,
304    Saturday,
305    Sunday,
306}
307
308/// Versioning strategies.
309#[derive(Deserialize, Debug, PartialEq)]
310#[serde(rename_all = "kebab-case")]
311pub enum VersioningStrategy {
312    Auto,
313    Increase,
314    IncreaseIfNecessary,
315    LockfileOnly,
316    Widen,
317}