Skip to content

Commit 1f2e43e

Browse files
author
Ismar Iljazovic
committed
feat: hook ownership model with external manager detection
Implement two-mode hook ownership: GitButler-managed (installs hooks directly) vs externally-managed (defers to prek/lefthook/husky). - Add hook_manager.rs: detect external managers via config + binary gate - Refactor managed_hooks.rs: ensure_managed_hooks() shared entry point - Add pre-push guard hook (blocks pushing gitbutler/workspace) - Add --no-hooks / --force-hooks escape hatches to setup/teardown - Hook lifecycle: staleness detection, auto-update, config persistence - Desktop app (integration.rs) uses same ensure_managed_hooks() path Addresses #12748 refactor: extract but-hooks crate from gitbutler-repo feat: add but hook CLI subcommands for hook manager integration Expose GitButler workspace guard and cleanup as standalone CLI commands that external hook managers can invoke from their configuration: - but hook pre-commit: blocks git commit on gitbutler/workspace - but hook post-checkout: info message when leaving workspace branch - but hook pre-push: blocks git push on gitbutler/workspace - but hook status: diagnostic view of hook ownership and integration state Follows up on hook-ownership-core.
1 parent f4921c5 commit 1f2e43e

File tree

49 files changed

+5991
-1087
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+5991
-1087
lines changed

Cargo.lock

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ members = [
3535
# 👉mostly powered by legacy, but will help to transition to `but-db` backing.
3636
"crates/but-meta", # 📄An interface to support Git-entity metadata;
3737
# 👉lacks tests
38+
"crates/but-hooks", # 📄Git hook management: external manager detection and managed hook installation.
3839
"crates/but-hunk-assignment", # 📄Assign uncommitted changes to stacks/lanes.
3940
# 👉uses `but-ctx`.
4041
"crates/but-hunk-dependency", # 📄Assuming it works, it feels close to 'Exemplary',
@@ -157,6 +158,7 @@ but-worktrees = { path = "crates/but-worktrees" }
157158
but-db = { path = "crates/but-db" }
158159
but-path = { path = "crates/but-path" }
159160
but-graph = { path = "crates/but-graph" }
161+
but-hooks = { path = "crates/but-hooks" }
160162
but-meta = { path = "crates/but-meta" }
161163
but-rules = { path = "crates/but-rules" }
162164
but-action = { path = "crates/but-action" }
@@ -212,6 +214,7 @@ gitbutler-workspace = { path = "crates/gitbutler-workspace" }
212214
rusqlite = { version = "0.39.0", features = ["bundled"] }
213215
backoff = "0.4.0"
214216
bstr = "1.12.1"
217+
which = "8.0.0"
215218
# Add the `tracing` or `tracing-detail` features to see more of gitoxide in the logs. Useful to see which programs it invokes.
216219
# When adjusting this, update `gix-testtools` as well!
217220
gix = { version = "0.81.0", git = "https://github.com/GitoxideLabs/gitoxide", rev = "700ad9ea517d8b2f2a2f7948d9e0bd0df1962a56", default-features = false, features = [

crates/but-api/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ gix = { workspace = true, features = ["worktree-mutation"] }
139139
open.workspace = true
140140
url = { version = "2.5", optional = true }
141141
uuid.workspace = true
142-
which = "8.0.0"
142+
which.workspace = true
143143
but-schemars.workspace = true
144144

145145
[dev-dependencies]

crates/but-core/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,10 @@ mod ext;
114114
pub use ext::ObjectStorageExt;
115115

116116
mod repo_ext;
117-
pub use repo_ext::{RepositoryExt, update_head_reference};
117+
pub use repo_ext::{
118+
GITBUTLER_COMMIT_AUTHOR_EMAIL, GITBUTLER_COMMIT_AUTHOR_NAME, RepositoryExt, commit_time,
119+
committer_signature, update_head_reference,
120+
};
118121

119122
/// Return `true` if `ref_name` looks like the standard GitButler workspace.
120123
///

crates/but-core/src/repo_ext.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -466,12 +466,14 @@ impl RepositoryExt for gix::Repository {
466466
}
467467
}
468468

469-
const GITBUTLER_COMMIT_AUTHOR_NAME: &str = "GitButler";
470-
const GITBUTLER_COMMIT_AUTHOR_EMAIL: &str = "gitbutler@gitbutler.com";
469+
/// The display name used for commits authored by GitButler itself.
470+
pub const GITBUTLER_COMMIT_AUTHOR_NAME: &str = "GitButler";
471+
/// The email address used for commits authored by GitButler itself.
472+
pub const GITBUTLER_COMMIT_AUTHOR_EMAIL: &str = "gitbutler@gitbutler.com";
471473

472474
/// Provide a signature with the GitButler author, and the current time or the time overridden
473475
/// depending on the value for `purpose`.
474-
fn committer_signature() -> gix::actor::Signature {
476+
pub fn committer_signature() -> gix::actor::Signature {
475477
gix::actor::Signature {
476478
name: GITBUTLER_COMMIT_AUTHOR_NAME.into(),
477479
email: GITBUTLER_COMMIT_AUTHOR_EMAIL.into(),
@@ -481,7 +483,7 @@ fn committer_signature() -> gix::actor::Signature {
481483

482484
/// Return the time of a commit as `now` unless the `overriding_variable_name` contains a parseable date,
483485
/// which is used instead.
484-
fn commit_time(overriding_variable_name: &str) -> gix::date::Time {
486+
pub fn commit_time(overriding_variable_name: &str) -> gix::date::Time {
485487
std::env::var(overriding_variable_name)
486488
.ok()
487489
.and_then(|time| gix::date::parse(&time, Some(std::time::SystemTime::now())).ok())

crates/but-hooks/Cargo.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
authors.workspace =true
3+
edition.workspace =true
4+
name ="but-hooks"
5+
publish =false
6+
rust-version.workspace=true
7+
version ="0.0.0"
8+
9+
[lib]
10+
doctest=false
11+
12+
[dependencies]
13+
but-core.workspace=true
14+
15+
anyhow.workspace =true
16+
gix.workspace =true
17+
tracing.workspace=true
18+
which.workspace =true
19+
20+
[dev-dependencies]
21+
temp-env ="0.3"
22+
tempfile.workspace=true
23+
24+
[lints]
25+
workspace=true

0 commit comments

Comments
 (0)