Skip to content

Commit c46fdfc

Browse files
committed
Workspace Rules - initial types
1 parent 59868be commit c46fdfc

File tree

4 files changed

+153
-0
lines changed

4 files changed

+153
-0
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ but-hunk-assignment = { path = "crates/but-hunk-assignment" }
7676
but-hunk-dependency = { path = "crates/but-hunk-dependency" }
7777
but-db = { path = "crates/but-db" }
7878
but-graph = { path = "crates/but-graph" }
79+
but-rules = { path = "crates/but-rules" }
7980
but-action = { path = "crates/but-action" }
8081
but-status = { path = "crates/but-status" }
8182
but-tools = { path = "crates/but-tools" }

crates/but-rules/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "but-rules"
3+
version = "0.0.0"
4+
edition = "2024"
5+
authors = ["GitButler <[email protected]>"]
6+
publish = false
7+
8+
9+
[lib]
10+
doctest = false
11+
12+
[dependencies]
13+
anyhow = "1.0.98"
14+
itertools.workspace = true
15+
serde.workspace = true
16+
regex = "1.11.1"
17+
chrono = { version = "0.4.41", features = [] }
18+
serde_regex = "1.1.0"

crates/but-rules/src/lib.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
#[derive(Serialize, Deserialize, Debug, Clone)]
4+
#[serde(rename_all = "camelCase")]
5+
pub struct WorkspaceRule {
6+
/// A UUID unique identifier for the rule.
7+
id: String,
8+
/// The time when the rule was created, represented as a Unix timestamp in milliseconds.
9+
created_at: chrono::NaiveDateTime,
10+
/// Whether the rule is currently enabled or not.
11+
enabled: bool,
12+
/// The trigger of the rule is what causes it to be evaluated in the app.
13+
trigger: Trigger,
14+
/// These filtes determine what files or changes the rule applies to.
15+
/// Within a rule, multiple filters are combined with OR logic (i.e. it's sufficient to match any of the filters)
16+
filters: Vec<Filter>,
17+
/// The action determines what happens to the files or changes that matched the filters.
18+
action: Action,
19+
}
20+
21+
/// Represents the kinds of events in the app that can cause a rule to be evaluated.
22+
#[derive(Serialize, Deserialize, Debug, Clone)]
23+
#[serde(rename_all = "camelCase")]
24+
pub enum Trigger {
25+
/// When a file is added, removed or modified in the Git worktree.
26+
FileSytemChange,
27+
}
28+
29+
/// A filter is a condition that determines what files or changes the rule applies to.
30+
/// Within a filter, multiple conditions are combined with AND logic (i.e. to match all conditions must be met)
31+
#[derive(Serialize, Deserialize, Debug, Clone)]
32+
#[serde(rename_all = "camelCase")]
33+
pub enum Filter {
34+
/// Matches the file path (relative to the repository root) against all provided regex patterns.
35+
#[serde(with = "serde_regex")]
36+
PathMatchesRegex(Vec<regex::Regex>),
37+
/// Match the file content against all provided regex patterns.
38+
#[serde(with = "serde_regex")]
39+
ContentMatchesRegex(Vec<regex::Regex>),
40+
/// Matches the file change operation type (e.g. addition, deletion, modification, rename)
41+
FileChangeType(TreeStatus),
42+
/// Matches the semantic type of the change.
43+
SemanticType(SemanticType),
44+
}
45+
46+
/// Represents the type of change that occurred in the Git worktree.
47+
/// Matches the TreeStatus of the TreeChange
48+
#[derive(Serialize, Deserialize, Debug, Clone)]
49+
#[serde(rename_all = "camelCase")]
50+
pub enum TreeStatus {
51+
/// Something was added or scheduled to be added.
52+
Addition,
53+
/// Something was deleted.
54+
Deletion,
55+
/// A tracked entry was modified, which might mean.
56+
Modification,
57+
/// An entry was renamed.
58+
Rename,
59+
}
60+
61+
/// Represents a semantic type of change that was inferred for the change.
62+
/// Typically this means a heuristic or an LLM determinded that a change represents a refactor, a new feature, a bug fix, or documentation update.
63+
#[derive(Serialize, Deserialize, Debug, Clone)]
64+
#[serde(rename_all = "camelCase")]
65+
pub enum SemanticType {
66+
/// A change that is a refactor, meaning it does not change the external behavior of the code but improves its structure.
67+
Refactor,
68+
/// A change that introduces a new feature or functionality to the codebase.
69+
NewFeature,
70+
/// A change that fixes a bug or an issue in the code.
71+
BugFix,
72+
/// A change that updates or adds documentation, such as code inline docs, comments or README files.
73+
Documentation,
74+
/// A change that is not recognized or does not fit into the predefined categories.
75+
UserDefined(String),
76+
}
77+
78+
/// Represents an action that can be taken based on the rule evaluation.
79+
/// An action can be either explicit, meaning the user defined something like "Assign in Lane A" or "Ammend into Commit X"
80+
/// or it is implicit, meaning the action was determined by heuristics or AI, such as "Assign to appropriate branch" or "Absorb in dependent commit".
81+
#[derive(Serialize, Deserialize, Debug, Clone)]
82+
#[serde(rename_all = "camelCase")]
83+
pub enum Action {
84+
/// An action that has an explicit operation defined by the user.
85+
Explicit(Operation),
86+
/// An action where the operation is determined by heuristics or AI.
87+
Implicit(ImplicitOperation),
88+
}
89+
90+
/// Represents the operation that a user can configure to be performed in an explicit action.
91+
#[derive(Serialize, Deserialize, Debug, Clone)]
92+
#[serde(rename_all = "camelCase")]
93+
pub enum Operation {
94+
/// Assign the matched changes to a specific stack ID.
95+
Assign { stack_id: String },
96+
/// Amend the matched changes into a specific commit.
97+
Amend { commit_id: String },
98+
/// Create a new commit with the matched changes on a specific branch.
99+
NewCommit { branch_name: String },
100+
}
101+
102+
/// Represents the implicit operation that is determined by heuristics or AI.
103+
#[derive(Serialize, Deserialize, Debug, Clone)]
104+
#[serde(rename_all = "camelCase")]
105+
pub enum ImplicitOperation {
106+
/// Assign the matched changes to the appropriate branch based on offline heuristics.
107+
AssignToAppropriateBranch,
108+
/// Absorb the matched changes into a dependent commit based on offline heuristics.
109+
AbsorbIntoDependentCommit,
110+
/// Perform an operation based on LLM-driven analysis and tool calling.
111+
LLMPrompt(String),
112+
}

0 commit comments

Comments
 (0)