Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cb17cfe

Browse files
xlai89extrawurst
andauthored
feat: support pre-push hooks (#2737)
Co-authored-by: extrawurst <776816+extrawurst@users.noreply.github.com>
1 parent 2374e00 commit cb17cfe

File tree

6 files changed

+90
-5
lines changed

6 files changed

+90
-5
lines changed

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
* increase MSRV from 1.81 to 1.82 [[@cruessler](https://github.com/cruessler)]
1111

1212
### Added
13+
* Support pre-push hook [[@xlai89](https://github.com/xlai89)] ([#1933](https://github.com/extrawurst/gitui/issues/1933))
1314
* Message tab supports pageUp and pageDown [[@xlai89](https://github.com/xlai89)] ([#2623](https://github.com/extrawurst/gitui/issues/2623))
1415
* Files and status tab support pageUp and pageDown [[@fatpandac](https://github.com/fatpandac)] ([#1951](https://github.com/extrawurst/gitui/issues/1951))
1516
* support loading custom syntax highlighting themes from a file [[@acuteenvy](https://github.com/acuteenvy)] ([#2565](https://github.com/gitui-org/gitui/pull/2565))

‎asyncgit/src/sync/hooks.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ pub fn hooks_prepare_commit_msg(
7272
.into())
7373
}
7474

75+
/// see `git2_hooks::hooks_pre_push`
76+
pub fn hooks_pre_push(repo_path: &RepoPath) -> Result<HookResult> {
77+
scope_time!("hooks_pre_push");
78+
79+
let repo = repo(repo_path)?;
80+
81+
Ok(git2_hooks::hooks_pre_push(&repo, None)?.into())
82+
}
83+
7584
#[cfg(test)]
7685
mod tests {
7786
use std::{ffi::OsString, io::Write as _, path::Path};

‎asyncgit/src/sync/mod.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ pub use diff::get_diff_commit;
6767
pub use git2::BranchType;
6868
pub use hooks::{
6969
hooks_commit_msg, hooks_post_commit, hooks_pre_commit,
70-
hooks_prepare_commit_msg, HookResult, PrepareCommitMsgSource,
70+
hooks_pre_push, hooks_prepare_commit_msg, HookResult,
71+
PrepareCommitMsgSource,
7172
};
7273
pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
7374
pub use ignore::add_to_ignore;

‎git2-hooks/src/lib.rs‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub const HOOK_POST_COMMIT: &str = "post-commit";
4444
pub const HOOK_PRE_COMMIT: &str = "pre-commit";
4545
pub const HOOK_COMMIT_MSG: &str = "commit-msg";
4646
pub const HOOK_PREPARE_COMMIT_MSG: &str = "prepare-commit-msg";
47+
pub const HOOK_PRE_PUSH: &str = "pre-push";
4748

4849
const HOOK_COMMIT_MSG_TEMP_FILE: &str = "COMMIT_EDITMSG";
4950

@@ -170,6 +171,20 @@ pub fn hooks_post_commit(
170171
hook.run_hook(&[])
171172
}
172173

174+
/// this hook is documented here <https://git-scm.com/docs/githooks#_pre_push>
175+
pub fn hooks_pre_push(
176+
repo: &Repository,
177+
other_paths: Option<&[&str]>,
178+
) -> Result<HookResult> {
179+
let hook = HookPaths::new(repo, other_paths, HOOK_PRE_PUSH)?;
180+
181+
if !hook.found() {
182+
return Ok(HookResult::NoHookFound);
183+
}
184+
185+
hook.run_hook(&[])
186+
}
187+
173188
pub enum PrepareCommitMsgSource {
174189
Message,
175190
Template,
@@ -658,4 +673,37 @@ exit 2
658673
)
659674
);
660675
}
676+
677+
#[test]
678+
fn test_pre_push_sh() {
679+
let (_td, repo) = repo_init();
680+
681+
let hook = b"#!/bin/sh
682+
exit 0
683+
";
684+
685+
create_hook(&repo, HOOK_PRE_PUSH, hook);
686+
687+
let res = hooks_pre_push(&repo, None).unwrap();
688+
689+
assert!(matches!(res, HookResult::Ok { .. }));
690+
}
691+
692+
#[test]
693+
fn test_pre_push_fail_sh() {
694+
let (_td, repo) = repo_init();
695+
696+
let hook = b"#!/bin/sh
697+
echo 'failed'
698+
exit 3
699+
";
700+
create_hook(&repo, HOOK_PRE_PUSH, hook);
701+
let res = hooks_pre_push(&repo, None).unwrap();
702+
let HookResult::RunNotSuccessful { code, stdout, .. } = res
703+
else {
704+
unreachable!()
705+
};
706+
assert_eq!(code.unwrap(), 3);
707+
assert_eq!(&stdout, "failed\n");
708+
}
661709
}

‎src/popups/push.rs‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use asyncgit::{
1616
extract_username_password_for_push,
1717
need_username_password_for_push, BasicAuthCredential,
1818
},
19-
get_branch_remote,
19+
get_branch_remote, hooks_pre_push,
2020
remotes::get_default_remote_for_push,
21-
RepoPathRef,
21+
HookResult,RepoPathRef,
2222
},
2323
AsyncGitNotification, AsyncPush, PushRequest, PushType,
2424
RemoteProgress, RemoteProgressState,
@@ -144,6 +144,19 @@ impl PushPopup {
144144
remote
145145
};
146146

147+
// run pre push hook - can reject push
148+
if let HookResult::NotOk(e) =
149+
hooks_pre_push(&self.repo.borrow())?
150+
{
151+
log::error!("pre-push hook failed: {e}");
152+
self.queue.push(InternalEvent::ShowErrorMsg(format!(
153+
"pre-push hook failed:\n{e}"
154+
)));
155+
self.pending = false;
156+
self.visible = false;
157+
return Ok(());
158+
}
159+
147160
self.pending = true;
148161
self.progress = None;
149162
self.git_push.request(PushRequest {

‎src/popups/push_tags.rs‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use asyncgit::{
1616
extract_username_password, need_username_password,
1717
BasicAuthCredential,
1818
},
19-
get_default_remote, AsyncProgress,PushTagsProgress,
20-
RepoPathRef,
19+
get_default_remote, hooks_pre_push,AsyncProgress,
20+
HookResult,PushTagsProgress,RepoPathRef,
2121
},
2222
AsyncGitNotification, AsyncPushTags, PushTagsRequest,
2323
};
@@ -84,6 +84,19 @@ impl PushTagsPopup {
8484
&mut self,
8585
cred: Option<BasicAuthCredential>,
8686
) -> Result<()> {
87+
// run pre push hook - can reject push
88+
if let HookResult::NotOk(e) =
89+
hooks_pre_push(&self.repo.borrow())?
90+
{
91+
log::error!("pre-push hook failed: {e}");
92+
self.queue.push(InternalEvent::ShowErrorMsg(format!(
93+
"pre-push hook failed:\n{e}"
94+
)));
95+
self.pending = false;
96+
self.visible = false;
97+
return Ok(());
98+
}
99+
87100
self.pending = true;
88101
self.progress = None;
89102
self.git_push.request(PushTagsRequest {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /