git_checks/
allow_robot.rs

1// Copyright Kitware, Inc.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use derive_builder::Builder;
10use git_checks_core::impl_prelude::*;
11
12/// A check to allow robots to skip all checks.
13///
14/// Any actions performed by the identity are waved through and all other checks are ignored.
15#[derive(Builder, Debug, Clone)]
16#[builder(field(private))]
17pub struct AllowRobot {
18    /// The identity of the robot.
19    ///
20    /// Configuration: Required
21    identity: Identity,
22}
23
24impl AllowRobot {
25    /// Create a new builder.
26    pub fn builder() -> AllowRobotBuilder {
27        Default::default()
28    }
29}
30
31impl BranchCheck for AllowRobot {
32    fn name(&self) -> &str {
33        "allow-robot"
34    }
35
36    fn check(&self, ctx: &CheckGitContext, _: &CommitId) -> Result<CheckResult, Box<dyn Error>> {
37        let mut result = CheckResult::new();
38
39        if *ctx.topic_owner() == self.identity {
40            result.whitelist();
41        }
42
43        Ok(result)
44    }
45}
46
47#[cfg(feature = "config")]
48pub(crate) mod config {
49    use git_checks_config::{register_checks, BranchCheckConfig, IntoCheck};
50    use git_workarea::Identity;
51    use serde::Deserialize;
52    #[cfg(test)]
53    use serde_json::json;
54
55    #[cfg(test)]
56    use crate::test;
57    use crate::AllowRobot;
58
59    /// Configuration for the `AllowRobot` check.
60    ///
61    /// The `name` and `email` fields are required and are both strings.
62    ///
63    /// This check is registered as a branch check with the name `"allow_robot"`.
64    ///
65    /// # Example
66    ///
67    /// ```json
68    /// {
69    ///     "name": "Robot Name",
70    ///     "email": "robot@email.invalid"
71    /// }
72    /// ```
73    #[derive(Deserialize, Debug)]
74    pub struct AllowRobotConfig {
75        name: String,
76        email: String,
77    }
78
79    impl IntoCheck for AllowRobotConfig {
80        type Check = AllowRobot;
81
82        fn into_check(self) -> Self::Check {
83            let identity = Identity::new(self.name, self.email);
84            AllowRobot::builder()
85                .identity(identity)
86                .build()
87                .expect("configuration mismatch for `AllowRobot`")
88        }
89    }
90
91    register_checks! {
92        AllowRobotConfig {
93            "allow_robot" => BranchCheckConfig,
94        },
95    }
96
97    #[test]
98    fn test_allow_robot_config_empty() {
99        let json = json!({});
100        let err = serde_json::from_value::<AllowRobotConfig>(json).unwrap_err();
101        test::check_missing_json_field(err, "name");
102    }
103
104    #[test]
105    fn test_allow_robot_config_name_is_required() {
106        let email = "robot@email.invalid";
107        let json = json!({
108            "email": email,
109        });
110        let err = serde_json::from_value::<AllowRobotConfig>(json).unwrap_err();
111        test::check_missing_json_field(err, "name");
112    }
113
114    #[test]
115    fn test_allow_robot_config_email_is_required() {
116        let name = "Robot Name";
117        let json = json!({
118            "name": name,
119        });
120        let err = serde_json::from_value::<AllowRobotConfig>(json).unwrap_err();
121        test::check_missing_json_field(err, "email");
122    }
123
124    #[test]
125    fn test_allow_robot_config_minimum_fields() {
126        let name = "Robot Name";
127        let email = "robot@email.invalid";
128        let json = json!({
129            "name": name,
130            "email": email,
131        });
132        let check: AllowRobotConfig = serde_json::from_value(json).unwrap();
133
134        assert_eq!(check.name, name);
135        assert_eq!(check.email, email);
136
137        let check = check.into_check();
138
139        assert_eq!(check.identity.name, name);
140        assert_eq!(check.identity.email, email);
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use git_checks_core::BranchCheck;
147    use git_workarea::Identity;
148
149    use crate::test::*;
150    use crate::AllowRobot;
151
152    const ALLOW_ROBOT_COMMIT: &str = "43adb8173eb6d7a39f98e1ec3351cf27414c9aa1";
153
154    #[test]
155    fn test_allow_robot_builder_default() {
156        assert!(AllowRobot::builder().build().is_err());
157    }
158
159    #[test]
160    fn test_allow_robot_builder_minimum_fields() {
161        assert!(AllowRobot::builder()
162            .identity(Identity::new("name", "email"))
163            .build()
164            .is_ok());
165    }
166
167    #[test]
168    fn test_allow_robot_name_branch() {
169        let check = AllowRobot::builder()
170            .identity(Identity::new("name", "email"))
171            .build()
172            .unwrap();
173        assert_eq!(BranchCheck::name(&check), "allow-robot");
174    }
175
176    #[test]
177    fn test_allow_robot_allowed() {
178        let check = AllowRobot::builder()
179            .identity(Identity::new(
180                "Rust Git Checks Tests",
181                "rust-git-checks@example.com",
182            ))
183            .build()
184            .unwrap();
185        let result = run_branch_check("test_allow_robot_allowed", ALLOW_ROBOT_COMMIT, check);
186
187        assert_eq!(result.warnings().len(), 0);
188        assert_eq!(result.alerts().len(), 0);
189        assert_eq!(result.errors().len(), 0);
190        assert!(!result.temporary());
191        assert!(result.allowed());
192        assert!(result.pass());
193    }
194
195    #[test]
196    fn test_allow_robot_not_robot_not_whitelisted() {
197        let check = AllowRobot::builder()
198            .identity(Identity::new(
199                "Rust Git Checks 7ests",
200                "rust-git-checks@example.com",
201            ))
202            .build()
203            .unwrap();
204        run_branch_check_ok(
205            "test_allow_robot_not_robot_not_whitelisted",
206            ALLOW_ROBOT_COMMIT,
207            check,
208        );
209    }
210}