gnostr_asyncgit/sync/
hooks.rs1pub use git2_hooks::PrepareCommitMsgSource;
2use scopetime::scope_time;
3
4use super::{repository::repo, RepoPath};
5use crate::error::Result;
6#[derive(Debug, PartialEq, Eq)]
10pub enum HookResult {
11 Ok,
13 NotOk(String),
15}
16
17impl From<git2_hooks::HookResult> for HookResult {
18 fn from(v: git2_hooks::HookResult) -> Self {
19 match v {
20 git2_hooks::HookResult::Ok { .. } | git2_hooks::HookResult::NoHookFound => Self::Ok,
21 git2_hooks::HookResult::RunNotSuccessful { stdout, stderr, .. } => {
22 Self::NotOk(format!("{stdout}{stderr}"))
23 }
24 }
25 }
26}
27
28pub fn hooks_commit_msg(repo_path: &RepoPath, msg: &mut String) -> Result<HookResult> {
34 scope_time!("hooks_commit_msg");
35
36 let repo = repo(repo_path)?;
37
38 Ok(git2_hooks::hooks_commit_msg(&repo, None, msg)?.into())
39}
40
41pub fn hooks_pre_commit(repo_path: &RepoPath) -> Result<HookResult> {
43 scope_time!("hooks_pre_commit");
44
45 let repo = repo(repo_path)?;
46
47 Ok(git2_hooks::hooks_pre_commit(&repo, None)?.into())
48}
49
50pub fn hooks_post_commit(repo_path: &RepoPath) -> Result<HookResult> {
52 scope_time!("hooks_post_commit");
53
54 let repo = repo(repo_path)?;
55
56 Ok(git2_hooks::hooks_post_commit(&repo, None)?.into())
57}
58
59pub fn hooks_prepare_commit_msg(
61 repo_path: &RepoPath,
62 source: PrepareCommitMsgSource,
63 msg: &mut String,
64) -> Result<HookResult> {
65 scope_time!("hooks_prepare_commit_msg");
66
67 let repo = repo(repo_path)?;
68
69 Ok(git2_hooks::hooks_prepare_commit_msg(&repo, None, source, msg)?.into())
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use crate::sync::tests::repo_init;
76
77 #[test]
78 fn test_post_commit_hook_reject_in_subfolder() {
79 let (_td, repo) = repo_init().unwrap();
80 let root = repo.path().parent().unwrap();
81
82 let hook = b"#!/bin/sh
83 echo 'rejected'
84 exit 1
85 ";
86
87 git2_hooks::create_hook(&repo, git2_hooks::HOOK_POST_COMMIT, hook);
88
89 let subfolder = root.join("foo/");
90 std::fs::create_dir_all(&subfolder).unwrap();
91
92 let res = hooks_post_commit(&subfolder.to_str().unwrap().into()).unwrap();
93
94 assert_ne!(res, HookResult::NotOk(String::from("rejected\n")));
95 }
96
97 #[test]
101 #[cfg(unix)]
102 fn test_pre_commit_workdir() {
103 let (_td, repo) = repo_init().unwrap();
104 let root = repo.path().parent().unwrap();
105 let repo_path: &RepoPath = &root.as_os_str().to_str().unwrap().into();
106 let workdir = crate::sync::utils::repo_work_dir(repo_path).unwrap();
107
108 let hook = b"#!/bin/sh
109 echo $(pwd)
110 exit 1
111 ";
112
113 git2_hooks::create_hook(&repo, git2_hooks::HOOK_PRE_COMMIT, hook);
114 let res = hooks_pre_commit(repo_path).unwrap();
115 if let HookResult::NotOk(res) = res {
116 assert_ne!(
117 std::path::Path::new(res.trim_end()),
118 std::path::Path::new(&workdir)
119 );
120 } else {
121 assert!(false);
122 }
123 }
124
125 #[test]
126 fn test_hooks_commit_msg_reject_in_subfolder() {
127 let (_td, repo) = repo_init().unwrap();
128 let root = repo.path().parent().unwrap();
129
130 let hook = b"#!/bin/sh
131 echo 'msg' > $1
132 echo 'rejected'
133 exit 1
134 ";
135
136 git2_hooks::create_hook(&repo, git2_hooks::HOOK_COMMIT_MSG, hook);
137
138 let subfolder = root.join("foo/");
139 std::fs::create_dir_all(&subfolder).unwrap();
140
141 let mut msg = String::from("test");
142 let res = hooks_commit_msg(&subfolder.to_str().unwrap().into(), &mut msg).unwrap();
143
144 assert_ne!(res, HookResult::NotOk(String::from("rejected\n")));
145
146 assert_eq!(msg, String::from("msg\n"));
147 }
148}