summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Paulo Pimenta Cabral <danielc777888@gmail.com>2020-01-30 14:57:54 +0200
committerGitHub <noreply@github.com>2020-01-30 14:57:54 +0200
commit7c198ca97edc24fe8373526ba4891430ce04b75f (patch)
tree1a6afb5250531daea0b466818a875043cd67a14d
parentfe60d2a0585f7e83c3091a4a567f10a92edcaa18 (diff)
parent805dd3e4d3cba8e7a2bda92d8c2c4f38d0c4e360 (diff)
Merge pull request #44 from jemstep/PYKE-11909-multiple-mainline-branches
Pyke 11909 multiple mainline branches
-rw-r--r--.capn3
-rw-r--r--Cargo.lock77
-rw-r--r--Cargo.toml6
-rw-r--r--readme.org17
-rw-r--r--src/config.rs22
-rw-r--r--src/git.rs264
-rw-r--r--src/lib.rs16
-rw-r--r--src/main.rs31
-rw-r--r--src/policies.rs24
-rw-r--r--tests/policies_test.rs41
-rw-r--r--tests/test-repo.git/refs/heads/.gitkeep0
-rw-r--r--tests/test-repo.git/refs/tags/.gitkeep0
12 files changed, 441 insertions, 60 deletions
diff --git a/.capn b/.capn
index d2cfc1d..3510184 100644
--- a/.capn
+++ b/.capn
@@ -1 +1,4 @@
+[git]
+mainlines = [ "master" ]
+
[prepend_branch_name]
diff --git a/Cargo.lock b/Cargo.lock
index 1f5de6e..f401d77 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,14 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
+name = "aho-corasick"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -42,6 +50,8 @@ dependencies = [
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quickcheck_macros 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -130,6 +140,15 @@ version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "env_logger"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "getrandom"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -229,6 +248,11 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "memchr"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "memoffset"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -296,6 +320,27 @@ dependencies = [
]
[[package]]
+name = "quickcheck"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quickcheck_macros"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -368,6 +413,22 @@ version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "regex"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -476,6 +537,14 @@ dependencies = [
]
[[package]]
+name = "thread_local"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -578,6 +647,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
+"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
@@ -592,6 +662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700"
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
+"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
"checksum git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
@@ -604,6 +675,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
+"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
@@ -613,6 +685,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
"checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097"
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
+"checksum quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f"
+"checksum quickcheck_macros 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "608c156fd8e97febc07dc9c2e2c80bf74cfc6ef26893eae3daf8bc2bc94a4b7f"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
@@ -621,6 +695,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43739f8831493b276363637423d3622d4bd6394ab6f0a9c4a552e208aeb7fddd"
"checksum rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8bf17de6f23b05473c437eb958b9c850bfc8af0961fe17b4cc92d5a627b4791"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87"
+"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
@@ -635,6 +711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum structopt-derive 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea692d40005b3ceba90a9fe7a78fa8d4b82b0ce627eebbffc329aab850f3410e"
"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
diff --git a/Cargo.toml b/Cargo.toml
index 5091f90..c0dcc0a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,4 +13,8 @@ serde_json = "1.0.40"
log = { version = "0.4.8", features = ["std", "serde"] }
chrono = "0.4.7"
rayon = "1.0.3"
-uuid = { version = "0.8.1", features = ["serde", "v4"] } \ No newline at end of file
+uuid = { version = "0.8.1", features = ["serde", "v4"] }
+
+[dev-dependencies]
+quickcheck = "0.9.2"
+quickcheck_macros = "0.9.1" \ No newline at end of file
diff --git a/readme.org b/readme.org
index c7790d1..995d998 100644
--- a/readme.org
+++ b/readme.org
@@ -85,6 +85,21 @@ project's repo. This configuration file is in TOML format.
This is an example ~.capn~ file: [[./.capn]]
*** Policies
+**** Git configuration
+There are some properties that are common across
+policies. Configuration of how certain Git conventions are followed
+are grouped into the ~[git]~ section, and may affect multiple
+policies.
+
+#+BEGIN_SRC toml
+ [git]
+
+ # The set of branches and patterns that are considered the 'mainline' by other policies.
+ # Supports globs and the special symbolic reference "HEAD".
+ # Default is [ "HEAD" ]
+ mainlines = [ "HEAD", "develop", "RC-*" ]
+#+END_SRC
+
**** Verify Git Commits
This policy ensures that all commits come from a trusted source, using
GPG keys. For this policy to work, Captain Git Hook must be installed
@@ -114,7 +129,7 @@ This is the config section for this policy:
recv_keys_par = true # run key requests to keyserver in parallel
skip_recv_keys = false # if true, do not fetch keys from the keyserver
- verify_different_authors = true # if true, merge commits to the head branch of the repo should have multiple authors in the branch
+ verify_different_authors = true # if true, merge commits to the mainline branch of the repo should have multiple authors in the branch
override_tag_pattern = "capn-override-*" # glob used to limit tags that are considered override tags (see Override Tags docs)
override_tags_required = 2 # the number of tags required to override signed commit rules
diff --git a/src/config.rs b/src/config.rs
index ec27ab6..e2a983e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -3,10 +3,26 @@ use toml;
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Config {
+ #[serde(default)]
+ pub git: GitConfig,
pub prepend_branch_name: Option<Unit>,
pub verify_git_commits: Option<VerifyGitCommitsConfig>,
}
+#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
+pub struct GitConfig {
+ #[serde(default = "GitConfig::default_mainlines")]
+ pub mainlines: Vec<String>,
+}
+
+impl Default for GitConfig {
+ fn default() -> GitConfig {
+ GitConfig {
+ mainlines: GitConfig::default_mainlines(),
+ }
+ }
+}
+
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct VerifyGitCommitsConfig {
pub author_domain: String,
@@ -49,3 +65,9 @@ impl Config {
toml::from_str(input)
}
}
+
+impl GitConfig {
+ fn default_mainlines() -> Vec<String> {
+ vec!["HEAD".into()]
+ }
+}
diff --git a/src/git.rs b/src/git.rs
index bc1bcf2..944497f 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -1,12 +1,13 @@
use crate::error::CapnError;
use crate::keyring::Keyring;
use git2;
-use git2::{ObjectType, Oid, Repository};
+use git2::{ErrorClass, ObjectType, Oid, Repository};
use std::cell::RefCell;
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
+use std::path::Path;
use std::process::*;
use std::str;
@@ -31,7 +32,6 @@ pub struct Tag {
}
pub trait Git: Sized {
- fn new() -> Result<Self, Box<dyn Error>>;
fn read_file(&self, path: &str) -> Result<String, Box<dyn Error>>;
fn write_git_file(
&self,
@@ -46,7 +46,7 @@ pub trait Git: Sized {
commit_id: Oid,
override_tag_pattern: &Option<String>,
) -> Result<Commit, Box<dyn Error>>;
- fn find_commits(
+ fn find_new_commits(
&self,
exclusions: &[Oid],
inclusions: &[Oid],
@@ -55,15 +55,15 @@ pub trait Git: Sized {
fn is_merge_commit(&self, commit_id: Oid) -> bool;
fn is_trivial_merge_commit(&self, commit: &Commit) -> Result<bool, Box<dyn Error>>;
- fn is_head(&self, ref_name: &str) -> Result<bool, Box<dyn Error>>;
- fn path(&self) -> &std::path::Path;
+ fn is_mainline(&self, ref_name: &str) -> Result<bool, Box<dyn Error>>;
+ fn path(&self) -> &Path;
fn verify_commit_signature(
- path: &std::path::Path,
+ path: &Path,
commit: &Commit,
keyring: &Keyring,
) -> Result<bool, Box<dyn Error>>;
fn verify_tag_signature(
- path: &std::path::Path,
+ path: &Path,
tag: &Tag,
keyring: &Keyring,
) -> Result<bool, Box<dyn Error>>;
@@ -77,18 +77,11 @@ pub trait Git: Sized {
pub struct LiveGit {
repo: Repository,
tag_cache: RefCell<HashMap<Option<String>, HashMap<Oid, Vec<Tag>>>>,
+ config: GitConfig,
}
impl Git for LiveGit {
- fn new() -> Result<Self, Box<dyn Error>> {
- let repo = Repository::discover("./")?;
- Ok(LiveGit {
- repo,
- tag_cache: RefCell::new(HashMap::new()),
- })
- }
-
- fn path(&self) -> &std::path::Path {
+ fn path(&self) -> &Path {
self.repo.path()
}
@@ -180,7 +173,7 @@ impl Git for LiveGit {
})
}
- fn find_commits(
+ fn find_new_commits(
&self,
exclusions: &[Oid],
inclusions: &[Oid],
@@ -193,7 +186,21 @@ impl Git for LiveGit {
for &exclusion in exclusions.iter().filter(|id| !id.is_zero()) {
revwalk.hide(exclusion)?;
}
- revwalk.hide_head()?;
+ for mainline in &self.config.mainlines {
+ if mainline == "HEAD" {
+ revwalk.hide_head()?;
+ } else if mainline.contains(|c| c == '?' || c == '*' || c == '[') {
+ revwalk.hide_glob(&format!("refs/heads/{}", mainline))?;
+ } else {
+ match revwalk.hide_ref(&format!("refs/heads/{}", mainline)) {
+ Ok(()) => {}
+ Err(e) if e.class() == ErrorClass::Reference => {
+ warn!("Failed to exclude mainline branch {}. Error: {}.\nThis could indicate that the branch doesn't exist.", mainline, e);
+ }
+ Err(e) => return Err(e.into()),
+ }
+ }
+ }
let commits = revwalk
.into_iter()
@@ -207,7 +214,7 @@ impl Git for LiveGit {
}
fn verify_tag_signature(
- path: &std::path::Path,
+ path: &Path,
tag: &Tag,
keyring: &Keyring,
) -> Result<bool, Box<dyn Error>> {
@@ -261,7 +268,7 @@ impl Git for LiveGit {
}
fn verify_commit_signature(
- path: &std::path::Path,
+ path: &Path,
commit: &Commit,
keyring: &Keyring,
) -> Result<bool, Box<dyn Error>> {
@@ -347,9 +354,34 @@ impl Git for LiveGit {
}
}
- fn is_head(&self, ref_name: &str) -> Result<bool, Box<dyn Error>> {
- let head = self.repo.head()?;
- Ok(Some(ref_name) == head.name())
+ fn is_mainline(&self, ref_name: &str) -> Result<bool, Box<dyn Error>> {
+ fn is_head(git: &LiveGit, ref_name: &str) -> Result<bool, Box<dyn Error>> {
+ let head = git.repo.head()?;
+ Ok(Some(ref_name) == head.name())
+ }
+ fn matches_glob(git: &LiveGit, ref_name: &str, glob: &str) -> Result<bool, Box<dyn Error>> {
+ git.repo
+ .references_glob(&format!("refs/heads/{}", glob))?
+ .names()
+ .map(|name| name.map(|n| n == ref_name))
+ .fold(Ok(false), |acc, next| {
+ acc.and_then(|a| next.map(|b| a || b).map_err(|e| e.into()))
+ })
+ }
+
+ self.config
+ .mainlines
+ .iter()
+ .map(|mainline_glob| {
+ if mainline_glob == "HEAD" {
+ is_head(self, ref_name)
+ } else {
+ matches_glob(self, ref_name, mainline_glob)
+ }
+ })
+ .fold(Ok(false), |acc, next| {
+ acc.and_then(|a| next.map(|b| a || b))
+ })
}
fn is_tag(&self, id: Oid) -> bool {
@@ -361,6 +393,24 @@ impl Git for LiveGit {
}
impl LiveGit {
+ pub fn default(path: impl AsRef<Path>) -> Result<Self, Box<dyn Error>> {
+ let repo = Repository::discover(path)?;
+ Ok(LiveGit {
+ repo,
+ tag_cache: RefCell::new(HashMap::new()),
+ config: GitConfig::default(),
+ })
+ }
+
+ pub fn new(path: impl AsRef<Path>, config: GitConfig) -> Result<Self, Box<dyn Error>> {
+ let repo = Repository::discover(path)?;
+ Ok(LiveGit {
+ repo,
+ tag_cache: RefCell::new(HashMap::new()),
+ config,
+ })
+ }
+
fn is_identical_tree_to_any_parent(commit: &git2::Commit<'_>) -> bool {
let tree_id = commit.tree_id();
commit.parents().any(|p| p.tree_id() == tree_id)
@@ -444,3 +494,171 @@ impl Drop for TempRepo {
}
}
}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use git2::{Oid, Reference};
+ use quickcheck_macros::quickcheck;
+
+ fn valid_mainlines(mainlines: &[String]) -> bool {
+ mainlines
+ .iter()
+ .all(|mainline| !mainline.contains('\u{0}') && Reference::is_valid_name(&mainline))
+ }
+
+ #[test]
+ fn is_mainline_with_default_config_only_identifies_head_branch() {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::default(format!("{}/tests/test-repo.git", project_root)).unwrap();
+ assert_eq!(git.is_mainline("refs/heads/master").unwrap(), true);
+ assert_eq!(git.is_mainline("refs/heads/tagged-branch").unwrap(), false);
+ }
+
+ #[test]
+ fn is_mainline_with_glob_config_does_not_identify_head_branch() {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::new(
+ format!("{}/tests/test-repo.git", project_root),
+ GitConfig {
+ mainlines: vec!["tagged-*".into()],
+ },
+ )
+ .unwrap();
+ assert_eq!(git.is_mainline("refs/heads/master").unwrap(), false);
+ assert_eq!(git.is_mainline("refs/heads/tagged-branch").unwrap(), true);
+ }
+
+ #[test]
+ fn is_mainline_with_literal_config_does_not_identify_head_branch() {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::new(
+ format!("{}/tests/test-repo.git", project_root),
+ GitConfig {
+ mainlines: vec!["tagged-branch".into()],
+ },
+ )
+ .unwrap();
+ assert_eq!(git.is_mainline("refs/heads/master").unwrap(), false);
+ assert_eq!(git.is_mainline("refs/heads/tagged-branch").unwrap(), true);
+ }
+
+ #[quickcheck]
+ fn is_mainline_fuzz(branch: String, mainlines: Vec<String>) {
+ if valid_mainlines(&mainlines) {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::new(
+ format!("{}/tests/test-repo.git", project_root),
+ GitConfig { mainlines },
+ )
+ .unwrap();
+ git.is_mainline(&branch).unwrap();
+ }
+ }
+
+ #[test]
+ fn is_mainline_with_multiple_glob_config_identifies_all_matches() {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::new(
+ format!("{}/tests/test-repo.git", project_root),
+ GitConfig {
+ mainlines: vec!["HEAD".into(), "tagged-*".into()],
+ },
+ )
+ .unwrap();
+ assert_eq!(git.is_mainline("refs/heads/master").unwrap(), true);
+ assert_eq!(git.is_mainline("refs/heads/tagged-branch").unwrap(), true);
+ }
+
+ #[test]
+ fn new_commits_off_master_with_default_config() {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::default(format!("{}/tests/test-repo.git", project_root)).unwrap();
+ let commits = git
+ .find_new_commits(
+ &[Oid::from_str("eb5e0185546b0bb1a13feec6b9ee8b39985fea42").unwrap()],
+ &[Oid::from_str("6004dfdb071c71e5e76ad55b924b576487e1c485").unwrap()],
+ &None,
+ )
+ .unwrap();
+ assert_eq!(commits.len(), 2)
+ }
+
+ #[test]
+ fn new_commits_off_master_with_configured_mainline_glob() {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::new(
+ format!("{}/tests/test-repo.git", project_root),
+ GitConfig {
+ mainlines: vec!["HEAD".into(), "valid-*".into()],
+ },
+ )
+ .unwrap();
+ let commits = git
+ .find_new_commits(
+ &[Oid::from_str("eb5e0185546b0bb1a13feec6b9ee8b39985fea42").unwrap()],
+ &[Oid::from_str("6004dfdb071c71e5e76ad55b924b576487e1c485").unwrap()],
+ &None,
+ )
+ .unwrap();
+ assert_eq!(commits.len(), 1)
+ }
+
+ #[test]
+ fn new_commits_off_master_with_configured_mainline_literal_branch_name() {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::new(
+ format!("{}/tests/test-repo.git", project_root),
+ GitConfig {
+ mainlines: vec!["HEAD".into(), "valid-branch".into()],
+ },
+ )
+ .unwrap();
+ let commits = git
+ .find_new_commits(
+ &[Oid::from_str("eb5e0185546b0bb1a13feec6b9ee8b39985fea42").unwrap()],
+ &[Oid::from_str("6004dfdb071c71e5e76ad55b924b576487e1c485").unwrap()],
+ &None,
+ )
+ .unwrap();
+ assert_eq!(commits.len(), 1)
+ }
+
+ #[test]
+ fn new_commits_off_master_with_configured_mainline_literal_branch_doesnt_exist() {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::new(
+ format!("{}/tests/test-repo.git", project_root),
+ GitConfig {
+ mainlines: vec!["HEAD".into(), "this-branch-does-not-exist-asdfg".into()],
+ },
+ )
+ .unwrap();
+ let commits = git
+ .find_new_commits(
+ &[Oid::from_str("eb5e0185546b0bb1a13feec6b9ee8b39985fea42").unwrap()],
+ &[Oid::from_str("6004dfdb071c71e5e76ad55b924b576487e1c485").unwrap()],
+ &None,
+ )
+ .unwrap();
+ assert_eq!(commits.len(), 2)
+ }
+
+ #[quickcheck]
+ fn new_commits_fuzz(mainlines: Vec<String>) {
+ if valid_mainlines(&mainlines) {
+ let project_root = env!("CARGO_MANIFEST_DIR");
+ let git = LiveGit::new(
+ format!("{}/tests/test-repo.git", project_root),
+ GitConfig { mainlines },
+ )
+ .unwrap();
+ git.find_new_commits(
+ &[Oid::from_str("eb5e0185546b0bb1a13feec6b9ee8b39985fea42").unwrap()],
+ &[Oid::from_str("6004dfdb071c71e5e76ad55b924b576487e1c485").unwrap()],
+ &None,
+ )
+ .unwrap();
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 4b6800b..8b7b247 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -47,13 +47,14 @@ pub struct PrePush {
}
pub fn prepare_commit_msg<F: Fs, G: Git>(
+ git: &G,
opt: PrepareCommitMsg,
config: Config,
) -> Result<PolicyResult, Box<dyn Error>> {
if opt.commit_source.is_none() {
vec![config
.prepend_branch_name
- .map(|_| prepend_branch_name::<F, G>(opt.commit_file))]
+ .map(|_| prepend_branch_name::<F, G>(git, opt.commit_file))]
.into_iter()
.flatten()
.collect()
@@ -66,6 +67,7 @@ pub fn prepare_commit_msg<F: Fs, G: Git>(
}
pub fn pre_push<G: Git, P: Gpg>(
+ git: &G,
gpg: P,
_opt: &PrePush,
config: &Config,
@@ -77,13 +79,14 @@ pub fn pre_push<G: Git, P: Gpg>(
vec![config
.verify_git_commits
.as_ref()
- .map(|c| verify_git_commits::<G, P>(gpg, c, remote_sha, local_sha, local_ref))]
+ .map(|c| verify_git_commits::<G, P>(git, gpg, c, remote_sha, local_sha, local_ref))]
.into_iter()
.flatten()
.collect()
}
pub fn pre_receive<G: Git, P: Gpg>(
+ git: &G,
gpg: P,
config: &Config,
old_value: &str,
@@ -93,22 +96,21 @@ pub fn pre_receive<G: Git, P: Gpg>(
vec![config
.verify_git_commits
.as_ref()
- .map(|c| verify_git_commits::<G, P>(gpg, c, old_value, new_value, ref_name))]
+ .map(|c| verify_git_commits::<G, P>(git, gpg, c, old_value, new_value, ref_name))]
.into_iter()
.flatten()
.collect()
}
-pub fn install_hooks<G: Git>() -> Result<(), Box<dyn Error>> {
- let repo = G::new()?;
- repo.write_git_file(
+pub fn install_hooks<G: Git>(git: &G) -> Result<(), Box<dyn Error>> {
+ git.write_git_file(
"hooks/prepare-commit-msg",
0o750,
r#"#!/bin/sh
capn prepare-commit-msg "$@"
"#,
)?;
- repo.write_git_file(
+ git.write_git_file(
"hooks/pre-push",
0o750,
r#"#!/bin/sh
diff --git a/src/main.rs b/src/main.rs
index 550023c..e31a274 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -63,18 +63,10 @@ fn main() {
quiet,
);
- let git = match LiveGit::new() {
- Ok(g) => g,
+ let config = match load_config() {
+ Ok(config) => config,
Err(e) => {
- error!("Failed to initialize Capn Githook. Error: {}\nPlease check that you are in a Git repo.", e);
- exit(1);
- }
- };
-
- let config = match git.read_config() {
- Ok(c) => c,
- Err(e) => {
- error!("Failed to read the .capn config file. Error: {}.\nPlease check that you are in a Git repo that has a .capn config file in the root of the repo.", e);
+ error!("Failed to initialize Capn Githook. Error: {}.\nPlease check that you are in a Git repo that has a .capn config file in the root of the repo.", e);
exit(1);
}
};
@@ -99,11 +91,20 @@ fn main() {
}
}
+fn load_config() -> Result<Config, Box<dyn Error>> {
+ // This is a necessary bootstrapping step, because we need a Git
+ // object to load the config, which is used to initialize the Git
+ // object used for the rest of the run.
+ let default_git = LiveGit::default("./")?;
+ default_git.read_config()
+}
+
fn execute_command(command: Command, config: Config) -> Result<PolicyResult, Box<dyn Error>> {
+ let git = LiveGit::new("./", config.git.clone())?;
match command {
Command::PrepareCommitMsg(args) => {
info!("Calling prepare-commit-msg");
- prepare_commit_msg::<LiveFs, LiveGit>(args, config)
+ prepare_commit_msg::<LiveFs, LiveGit>(&git, args, config)
}
Command::PrePush(args) => {
info!("Calling pre-push");
@@ -113,7 +114,7 @@ fn execute_command(command: Command, config: Config) -> Result<PolicyResult, Box
match (fields.next(), fields.next(), fields.next(), fields.next()) {
(Some(local_ref), Some(local_sha), Some(remote_ref), Some(remote_sha)) => {
info!("Running pre-push for: {} {} {} {}", local_ref, local_sha, remote_ref, remote_sha);
- pre_push::<LiveGit, _>(build_gpg_client(&config), &args, &config, local_ref, local_sha, remote_ref, remote_sha)
+ pre_push::<LiveGit, _>(&git, build_gpg_client(&config), &args, &config, local_ref, local_sha, remote_ref, remote_sha)
},
_ => {
warn!("Expected parameters not received on stdin. Line received was: {}", line);
@@ -132,7 +133,7 @@ fn execute_command(command: Command, config: Config) -> Result<PolicyResult, Box
match (fields.next(), fields.next(), fields.next()) {
(Some(old_value), Some(new_value), Some(ref_name)) => {
info!("Running pre-receive for: {} {} {}", old_value, new_value, ref_name);
- pre_receive::<LiveGit, _>(build_gpg_client(&config), &config, old_value, new_value, ref_name)
+ pre_receive::<LiveGit, _>(&git, build_gpg_client(&config), &config, old_value, new_value, ref_name)
},
_ => {
warn!("Expected parameters not received on stdin. Line received was: {}", line);
@@ -143,7 +144,7 @@ fn execute_command(command: Command, config: Config) -> Result<PolicyResult, Box
.flatten()
.collect()
}
- Command::InstallHooks => install_hooks::<LiveGit>().map(|_| PolicyResult::Ok),
+ Command::InstallHooks => install_hooks(&git).map(|_| PolicyResult::Ok),
}
}
diff --git a/src/policies.rs b/src/policies.rs
index 821b6f5..eb5dcee 100644
--- a/src/policies.rs
+++ b/src/policies.rs
@@ -71,17 +71,18 @@ impl iter::FromIterator<PolicyResult> for PolicyResult {
}
pub fn prepend_branch_name<F: Fs, G: Git>(
+ git: &G,
commit_file: PathBuf,
) -> Result<PolicyResult, Box<dyn Error>> {
info!("Executing policy: prepend_branch_name");
- let git = G::new()?;
let branch = git.current_branch()?;
F::prepend_string_to_file(branch, commit_file)?;
Ok(PolicyResult::Ok)
}
pub fn verify_git_commits<G: Git, P: Gpg>(
+ git: &G,
gpg: P,
config: &VerifyGitCommitsConfig,
old_value: &str,
@@ -89,7 +90,6 @@ pub fn verify_git_commits<G: Git, P: Gpg>(
ref_name: &str,
) -> Result<PolicyResult, Box<dyn Error>> {
info!("Executing policy: verify_git_commits");
- let git = G::new()?;
let start = Instant::now();
let old_commit_id = Oid::from_str(old_value)?;
let new_commit_id = Oid::from_str(new_value)?;
@@ -102,7 +102,7 @@ pub fn verify_git_commits<G: Git, P: Gpg>(
debug!("Tag detected, no commits to verify.")
} else {
let all_commits = commits_to_verify(
- &git,
+ git,
old_commit_id,
new_commit_id,
&config.override_tag_pattern,
@@ -117,14 +117,14 @@ pub fn verify_git_commits<G: Git, P: Gpg>(
Keyring::from_team_fingerprints_file(git.read_file(&config.team_fingerprints_file)?);
let manually_verified_commmits = find_and_verify_override_tags(
- &git,
+ git,
&gpg,
&all_commits,
config.override_tags_required,
&mut keyring,
)?;
let not_manually_verified_commits = commits_to_verify_excluding_manually_verified(
- &git,
+ git,
old_commit_id,
new_commit_id,
manually_verified_commmits,
@@ -141,7 +141,7 @@ pub fn verify_git_commits<G: Git, P: Gpg>(
if config.verify_commit_signatures {
policy_result = policy_result.and(verify_commit_signatures::<G, P>(
- &git,
+ git,
&gpg,
&not_manually_verified_commits,
&mut keyring,
@@ -151,7 +151,7 @@ pub fn verify_git_commits<G: Git, P: Gpg>(
if config.verify_different_authors {
policy_result = policy_result.and(verify_different_authors::<G>(
&all_commits,
- &git,
+ git,
old_commit_id,
new_commit_id,
ref_name,
@@ -173,7 +173,7 @@ fn commits_to_verify<G: Git>(
new_commit_id: Oid,
override_tag_pattern: &Option<String>,
) -> Result<Vec<Commit>, Box<dyn Error>> {
- git.find_commits(&[old_commit_id], &[new_commit_id], override_tag_pattern)
+ git.find_new_commits(&[old_commit_id], &[new_commit_id], override_tag_pattern)
}
fn commits_to_verify_excluding_manually_verified<G: Git>(
@@ -185,7 +185,7 @@ fn commits_to_verify_excluding_manually_verified<G: Git>(
) -> Result<Vec<Commit>, Box<dyn Error>> {
let mut to_exclude = manually_verified;
to_exclude.push(old_commit_id);
- git.find_commits(&to_exclude, &[new_commit_id], override_tag_pattern)
+ git.find_new_commits(&to_exclude, &[new_commit_id], override_tag_pattern)
}
fn find_and_verify_override_tags<G: Git, P: Gpg>(
@@ -309,10 +309,10 @@ fn verify_different_authors<G: Git>(
) -> Result<PolicyResult, Box<dyn Error>> {
let new_branch = old_commit_id.is_zero();
let is_merge = git.is_merge_commit(new_commit_id);
- let is_head = git.is_head(ref_name)?;
+ let is_mainline = git.is_mainline(ref_name)?;
- if !is_head {
- info!("Multiple author verification passed for {}: Not updating the head of the repo, does not require multiple authors", new_commit_id);
+ if !is_mainline {
+ info!("Multiple author verification passed for {}: Not updating a mainline branch, does not require multiple authors", new_commit_id);
Ok(PolicyResult::Ok)
} else if !is_merge {
info!("Multiple author verification passed for {}: Not a merge commit, does not require multiple authors", new_commit_id);
diff --git a/tests/policies_test.rs b/tests/policies_test.rs
index cc2a5f3..b5708dd 100644
--- a/tests/policies_test.rs
+++ b/tests/policies_test.rs
@@ -1,5 +1,5 @@
use capn;
-use capn::config::{Config, VerifyGitCommitsConfig};
+use capn::config::{Config, GitConfig, VerifyGitCommitsConfig};
use capn::policies;
use capn::git::LiveGit;
@@ -63,10 +63,12 @@ fn verify_commits_config() -> VerifyGitCommitsConfig {
fn verify_git_commits_happy_path_from_empty_through_pre_receive() {
before_all();
let config = Config {
+ git: GitConfig::default(),
prepend_branch_name: None,
verify_git_commits: Some(verify_commits_config()),
};
let result = capn::pre_receive::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&config,
"0000000000000000000000000000000000000000",
@@ -81,6 +83,7 @@ fn verify_git_commits_happy_path_from_empty_through_pre_receive() {
fn verify_git_commits_happy_path_from_empty() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"0000000000000000000000000000000000000000",
@@ -95,6 +98,7 @@ fn verify_git_commits_happy_path_from_empty() {
fn verify_git_commits_happy_path_from_existing() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"7f9763e189ade34345e683ab7e0c22d164280452",
@@ -109,6 +113,7 @@ fn verify_git_commits_happy_path_from_existing() {
fn verify_git_commits_happy_path_unsigned_trivial_no_fast_forward_merge() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -123,6 +128,7 @@ fn verify_git_commits_happy_path_unsigned_trivial_no_fast_forward_merge() {
fn verify_git_commits_happy_path_unsigned_trivial_merge() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -137,6 +143,7 @@ fn verify_git_commits_happy_path_unsigned_trivial_merge() {
fn verify_git_commits_single_unsigned_commit() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -151,6 +158,7 @@ fn verify_git_commits_single_unsigned_commit() {
fn verify_git_commits_single_unsigned_commit_new_branch() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"0000000000000000000000000000000000000000",
@@ -165,6 +173,7 @@ fn verify_git_commits_single_unsigned_commit_new_branch() {
fn verify_git_commits_unsigned_commit_being_merged_in() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -179,6 +188,7 @@ fn verify_git_commits_unsigned_commit_being_merged_in() {
fn verify_git_commits_unsigned_commit_behind_a_merge_commit() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -193,6 +203,7 @@ fn verify_git_commits_unsigned_commit_behind_a_merge_commit() {
fn verify_git_commits_invalid_author() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -207,6 +218,7 @@ fn verify_git_commits_invalid_author() {
fn verify_git_commits_code_injected_into_unsigned_merge() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -222,6 +234,7 @@ fn verify_git_commits_happy_path_pushing_previously_checked_merge_commit() {
// This is an edge case for checking that merges have multiple authors
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"3eb315d10e2ad89555d7bfc78a1db1ce07bce434",
@@ -236,6 +249,7 @@ fn verify_git_commits_happy_path_pushing_previously_checked_merge_commit() {
fn verify_git_commits_author_merged_own_code_not_on_head() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -247,9 +261,31 @@ fn verify_git_commits_author_merged_own_code_not_on_head() {
}
#[test]
+fn verify_git_commits_author_merged_own_code_on_configured_mainline() {
+ before_all();
+ let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::new(
+ "./",
+ GitConfig {
+ mainlines: vec!["valid-*".into()],
+ },
+ )
+ .unwrap(),
+ MockGpg,
+ &verify_commits_config(),
+ "eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
+ "6004dfdb071c71e5e76ad55b924b576487e1c485",
+ "refs/heads/valid-branch",
+ )
+ .unwrap();
+ assert!(result.is_err());
+}
+
+#[test]
fn verify_git_commits_author_merged_own_code_on_head() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -264,6 +300,7 @@ fn verify_git_commits_author_merged_own_code_on_head() {
fn verify_git_commits_author_merged_own_code_on_head_with_tag() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"eb5e0185546b0bb1a13feec6b9ee8b39985fea42",
@@ -278,6 +315,7 @@ fn verify_git_commits_author_merged_own_code_on_head_with_tag() {
fn verify_tagged_git_commits_override_rules() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&verify_commits_config(),
"7f9763e189ade34345e683ab7e0c22d164280452",
@@ -292,6 +330,7 @@ fn verify_tagged_git_commits_override_rules() {
fn verify_tagged_git_commits_not_overridden_if_not_enough_tags() {
before_all();
let result = policies::verify_git_commits::<LiveGit, MockGpg>(
+ &LiveGit::default("./").unwrap(),
MockGpg,
&VerifyGitCommitsConfig {
override_tags_required: 2,
diff --git a/tests/test-repo.git/refs/heads/.gitkeep b/tests/test-repo.git/refs/heads/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test-repo.git/refs/heads/.gitkeep
diff --git a/tests/test-repo.git/refs/tags/.gitkeep b/tests/test-repo.git/refs/tags/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test-repo.git/refs/tags/.gitkeep