use derive_builder::Builder;
use git_checks_core::impl_prelude::*;
#[derive(Builder, Debug, Default, Clone, Copy)]
#[builder(field(private))]
pub struct RejectSymlinks {}
impl RejectSymlinks {
pub fn builder() -> RejectSymlinksBuilder {
RejectSymlinksBuilder::default()
}
}
impl ContentCheck for RejectSymlinks {
fn name(&self) -> &str {
"reject-symlinks"
}
fn check(
&self,
_: &CheckGitContext,
content: &dyn Content,
) -> Result<CheckResult, Box<dyn Error>> {
let mut result = CheckResult::new();
for diff in content.diffs() {
match diff.status {
StatusChange::Added | StatusChange::Modified(_) => (),
_ => continue,
}
if diff.new_mode == "120000" {
result.add_error(format!(
"{}adds a symlink at `{}` which is not allowed.",
commit_prefix(content),
diff.name,
));
}
}
Ok(result)
}
}
#[cfg(feature = "config")]
pub(crate) mod config {
use git_checks_config::{register_checks, CommitCheckConfig, IntoCheck, TopicCheckConfig};
use serde::Deserialize;
#[cfg(test)]
use serde_json::json;
use crate::RejectSymlinks;
#[derive(Deserialize, Debug)]
pub struct RejectSymlinksConfig {}
impl IntoCheck for RejectSymlinksConfig {
type Check = RejectSymlinks;
fn into_check(self) -> Self::Check {
RejectSymlinks::default()
}
}
register_checks! {
RejectSymlinksConfig {
"reject_symlinks" => CommitCheckConfig,
"reject_symlinks/topic" => TopicCheckConfig,
},
}
#[test]
fn test_reject_symlinks_config_empty() {
let json = json!({});
let check: RejectSymlinksConfig = serde_json::from_value(json).unwrap();
let _ = check.into_check();
}
}
#[cfg(test)]
mod tests {
use git_checks_core::{Check, TopicCheck};
use crate::test::*;
use crate::RejectSymlinks;
const BAD_TOPIC: &str = "00ffdf352196c16a453970de022a8b4343610ccf";
const DELETE_TOPIC: &str = "59ebc7302ce05ec21e396e508be99f8dc2924c2d";
const FIX_TOPIC: &str = "d93ffc2e8b782ba8dce2278dd86fda0df80f454b";
#[test]
fn test_reject_symlinks_builder_default() {
assert!(RejectSymlinks::builder().build().is_ok());
}
#[test]
fn test_reject_symlinks_name_commit() {
let check = RejectSymlinks::default();
assert_eq!(Check::name(&check), "reject-symlinks");
}
#[test]
fn test_reject_symlinks_name_topic() {
let check = RejectSymlinks::default();
assert_eq!(TopicCheck::name(&check), "reject-symlinks");
}
#[test]
fn test_reject_symlinks() {
let check = RejectSymlinks::default();
let result = run_check("test_reject_symlinks", BAD_TOPIC, check);
test_result_errors(result, &[
"commit 00ffdf352196c16a453970de022a8b4343610ccf adds a symlink at `absolute-link` \
which is not allowed.",
"commit 00ffdf352196c16a453970de022a8b4343610ccf adds a symlink at `broken-link` \
which is not allowed.",
"commit 00ffdf352196c16a453970de022a8b4343610ccf adds a symlink at `inside-link` \
which is not allowed.",
"commit 00ffdf352196c16a453970de022a8b4343610ccf adds a symlink at `outside-link` \
which is not allowed.",
]);
}
#[test]
fn test_reject_symlinks_topic() {
let check = RejectSymlinks::default();
let result = run_topic_check("test_reject_symlinks_topic", BAD_TOPIC, check);
test_result_errors(
result,
&[
"adds a symlink at `absolute-link` which is not allowed.",
"adds a symlink at `broken-link` which is not allowed.",
"adds a symlink at `inside-link` which is not allowed.",
"adds a symlink at `outside-link` which is not allowed.",
],
);
}
#[test]
fn test_reject_symlinks_topic_fixed() {
let check = RejectSymlinks::default();
run_topic_check_ok("test_reject_symlinks_topic_fixed", FIX_TOPIC, check);
}
#[test]
fn test_reject_symlinks_delete_file() {
let check = RejectSymlinks::default();
let conf = make_check_conf(&check);
let result = test_check_base(
"test_reject_symlinks_delete_file",
DELETE_TOPIC,
BAD_TOPIC,
&conf,
);
test_result_ok(result);
}
#[test]
fn test_reject_symlinks_delete_file_topic() {
let check = RejectSymlinks::default();
run_topic_check_ok(
"test_reject_symlinks_delete_file_topic",
DELETE_TOPIC,
check,
);
}
}