git_checks/
reject_merges.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 which denies merge commits, including octopus merges.
13#[derive(Builder, Debug, Default, Clone, Copy)]
14#[builder(field(private))]
15pub struct RejectMerges {}
16
17impl RejectMerges {
18    /// Create a new builder.
19    pub fn builder() -> RejectMergesBuilder {
20        Default::default()
21    }
22}
23
24impl Check for RejectMerges {
25    fn name(&self) -> &str {
26        "reject-merges"
27    }
28
29    fn check(&self, _: &CheckGitContext, commit: &Commit) -> Result<CheckResult, Box<dyn Error>> {
30        let mut result = CheckResult::new();
31
32        if commit.parents.len() > 1 {
33            result.add_error(format!(
34                "commit {} not allowed; it is a merge commit.",
35                commit.sha1,
36            ));
37        }
38
39        Ok(result)
40    }
41}
42
43#[cfg(feature = "config")]
44pub(crate) mod config {
45    use git_checks_config::{register_checks, CommitCheckConfig, IntoCheck};
46    use serde::Deserialize;
47    #[cfg(test)]
48    use serde_json::json;
49
50    use crate::RejectMerges;
51
52    /// Configuration for the `RejectMerges` check.
53    ///
54    /// No configuration available.
55    ///
56    /// This check is registered as a commit check with the name `"reject_merges"` and a topic
57    /// check with the name `"reject_merges/topic"`.
58    #[derive(Deserialize, Debug)]
59    pub struct RejectMergesConfig {}
60
61    impl IntoCheck for RejectMergesConfig {
62        type Check = RejectMerges;
63
64        fn into_check(self) -> Self::Check {
65            Default::default()
66        }
67    }
68
69    register_checks! {
70        RejectMergesConfig {
71            "reject_merges" => CommitCheckConfig,
72        },
73    }
74
75    #[test]
76    fn test_reject_merges_config_empty() {
77        let json = json!({});
78        let check: RejectMergesConfig = serde_json::from_value(json).unwrap();
79
80        let _ = check.into_check();
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use git_checks_core::Check;
87
88    use crate::test::*;
89    use crate::RejectMerges;
90
91    const NO_MERGES_TOPIC: &str = "2fab950c4ace0584760e00caae1bb7913b07494e";
92    const WITH_MERGES_TOPIC: &str = "92f545fa6c9326fe11dfb69c3ee01af285b595f4";
93    const OCTOPUS_MERGES_TOPIC: &str = "4447a8eddbccac61daa6b55642e46156011d36cb";
94
95    #[test]
96    fn test_reject_merges_builder_default() {
97        assert!(RejectMerges::builder().build().is_ok());
98    }
99
100    #[test]
101    fn test_reject_merges_name_commit() {
102        let check = RejectMerges::default();
103        assert_eq!(Check::name(&check), "reject-merges");
104    }
105
106    #[test]
107    fn test_reject_merges_name_topic() {
108        let check = RejectMerges::default();
109        assert_eq!(Check::name(&check), "reject-merges");
110    }
111
112    #[test]
113    fn test_reject_merges_no_merges() {
114        let check = RejectMerges::default();
115        run_check_ok("test_reject_merges_no_merges", NO_MERGES_TOPIC, check);
116    }
117
118    #[test]
119    fn test_reject_merges_with_merges() {
120        let check = RejectMerges::default();
121        let result = run_check("test_reject_merges_with_merges", WITH_MERGES_TOPIC, check);
122        test_result_errors(result, &[
123            "commit 92f545fa6c9326fe11dfb69c3ee01af285b595f4 not allowed; it is a merge commit.",
124        ]);
125    }
126
127    #[test]
128    fn test_reject_merges_octopus_merges() {
129        let check = RejectMerges::default();
130        let result = run_check("test_reject_merges_no_merges", OCTOPUS_MERGES_TOPIC, check);
131        test_result_errors(result, &[
132            "commit 4447a8eddbccac61daa6b55642e46156011d36cb not allowed; it is a merge commit.",
133        ]);
134    }
135}