Skip to content

Commit d02b405

Browse files
committed
BUTCLI: adds the ability to mark stack for auto assignments
1 parent f9dafa0 commit d02b405

File tree

9 files changed

+70
-1
lines changed

9 files changed

+70
-1
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/but-rules/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ pub fn list_rules(ctx: &mut CommandContext) -> anyhow::Result<Vec<WorkspaceRule>
292292
Ok(rules)
293293
}
294294

295-
fn process_rules(ctx: &mut CommandContext) -> anyhow::Result<()> {
295+
pub fn process_rules(ctx: &mut CommandContext) -> anyhow::Result<()> {
296296
let wt_changes = but_core::diff::worktree_changes(&ctx.gix_repo()?)?;
297297

298298
let dependencies = hunk_dependencies_for_workspace_changes_by_worktree_dir(

crates/but/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ anyhow.workspace = true
3030
rmcp.workspace = true
3131
command-group = { version = "5.0.1", features = ["with-tokio"] }
3232
sysinfo = "0.36.0"
33+
regex = "1.11.1"
3334
gitbutler-project.workspace = true
3435
gix.workspace = true
3536
but-core.workspace = true
@@ -42,6 +43,7 @@ but-hunk-assignment.workspace = true
4243
but-hunk-dependency.workspace = true
4344
but-claude.workspace = true
4445
but-tools.workspace = true
46+
but-rules.workspace = true
4547
gitbutler-command-context.workspace = true
4648
gitbutler-serde.workspace = true
4749
gitbutler-stack.workspace = true

crates/but/src/args.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ For examples see `but rub --help`."
4242
/// The target entity to combine with the source
4343
target: String,
4444
},
45+
/// Creates a rule for auto-assigning or auto-comitting
46+
Mark {
47+
/// The target entity that will be marked
48+
target: String,
49+
},
4550
/// Starts up the MCP server.
4651
Mcp {
4752
/// Starts the internal MCP server which has more granular tools.

crates/but/src/log/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::id::CliId;
1414
pub(crate) fn commit_graph(repo_path: &Path, _json: bool) -> anyhow::Result<()> {
1515
let project = Project::from_path(repo_path).expect("Failed to create project from path");
1616
let ctx = &mut CommandContext::open(&project, AppSettings::load_from_default_path_creating()?)?;
17+
but_rules::process_rules(ctx).ok(); // TODO: this is doing double work (dependencies can be reused)
1718
let stacks = stacks(ctx)?
1819
.iter()
1920
.filter_map(|s| s.id.map(|id| stack_details(ctx, id)))

crates/but/src/main.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use but_claude::hooks::OutputAsJson;
99
mod command;
1010
mod id;
1111
mod log;
12+
mod mark;
1213
mod mcp;
1314
mod mcp_internal;
1415
mod metrics;
@@ -98,6 +99,15 @@ async fn main() -> Result<()> {
9899
metrics_if_configured(app_settings, CommandName::Rub, props(start, &result)).ok();
99100
Ok(())
100101
}
102+
Subcommands::Mark { target } => {
103+
let result = mark::handle(&args.current_dir, args.json, target)
104+
.context("Can't mark this. Taaaa-na-na-na. Can't mark this.");
105+
if let Err(e) = &result {
106+
eprintln!("{} {}", e, e.root_cause());
107+
}
108+
metrics_if_configured(app_settings, CommandName::Rub, props(start, &result)).ok();
109+
Ok(())
110+
}
101111
}
102112
}
103113

crates/but/src/mark/mod.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use std::path::Path;
2+
3+
use crate::rub::branch_name_to_stack_id;
4+
use anyhow::bail;
5+
use but_rules::Operation;
6+
use but_settings::AppSettings;
7+
use gitbutler_command_context::CommandContext;
8+
use gitbutler_project::Project;
9+
pub(crate) fn handle(repo_path: &Path, _json: bool, target_str: &str) -> anyhow::Result<()> {
10+
let project = Project::from_path(repo_path).expect("Failed to create project from path");
11+
let ctx = &mut CommandContext::open(&project, AppSettings::load_from_default_path_creating()?)?;
12+
let target_result = crate::id::CliId::from_str(ctx, target_str)?;
13+
if target_result.len() != 1 {
14+
return Err(anyhow::anyhow!(
15+
"Target {} is ambiguous: {:?}",
16+
target_str,
17+
target_result
18+
));
19+
}
20+
match target_result[0].clone() {
21+
crate::id::CliId::Branch { name } => mark_branch(ctx, name),
22+
crate::id::CliId::Commit { oid } => mark_commit(oid),
23+
_ => bail!("Nope"),
24+
}
25+
}
26+
27+
fn mark_commit(_oid: gix::ObjectId) -> anyhow::Result<()> {
28+
bail!("Not implemented yet");
29+
}
30+
31+
fn mark_branch(ctx: &mut CommandContext, branch_name: String) -> anyhow::Result<()> {
32+
let stack_id =
33+
branch_name_to_stack_id(ctx, Some(&branch_name))?.expect("Cant find stack for this branch");
34+
let action = but_rules::Action::Explicit(Operation::Assign {
35+
target: but_rules::StackTarget::StackId(stack_id.to_string()),
36+
});
37+
let req = but_rules::CreateRuleRequest {
38+
trigger: but_rules::Trigger::FileSytemChange,
39+
filters: vec![but_rules::Filter::PathMatchesRegex(regex::Regex::new(
40+
".*",
41+
)?)],
42+
action,
43+
};
44+
but_rules::create_rule(ctx, req)?;
45+
println!("Changes will be assigned to → {}", branch_name);
46+
Ok(())
47+
}

crates/but/src/rub/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::path::Path;
22

33
use anyhow::bail;
4+
pub(crate) use assign::branch_name_to_stack_id;
45
use but_settings::AppSettings;
56
use colored::Colorize;
67
use gitbutler_command_context::CommandContext;

crates/but/src/status/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::id::CliId;
1515
pub(crate) fn worktree(repo_path: &Path, _json: bool) -> anyhow::Result<()> {
1616
let project = Project::from_path(repo_path).expect("Failed to create project from path");
1717
let ctx = &mut CommandContext::open(&project, AppSettings::load_from_default_path_creating()?)?;
18+
but_rules::process_rules(ctx).ok(); // TODO: this is doing double work (dependencies can be reused)
1819

1920
let stack_id_to_branch = crate::log::stacks(ctx)?
2021
.iter()

0 commit comments

Comments
 (0)