Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/assets/hooks/post-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
set -eu

exec sce hooks post-commit "$@"
exec sce hooks post-commit --vcs git "$@"
5 changes: 4 additions & 1 deletion cli/src/cli_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,10 @@ pub enum HooksSubcommand {
CommitMsg { message_file: PathBuf },

#[command(about = "Run post-commit hook")]
PostCommit,
PostCommit {
#[arg(long = "vcs")]
vcs: Option<String>,
},

#[command(about = "Run post-rewrite hook (reads pairs from STDIN)")]
PostRewrite { rewrite_method: String },
Expand Down
21 changes: 16 additions & 5 deletions cli/src/services/agent_trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,23 @@ fn generate_agent_trace_id(commit_time: DateTime<FixedOffset>) -> Result<String>
pub struct AgentTraceMetadataInput<'a> {
pub commit_timestamp: &'a str,
pub commit_revision: &'a str,
pub vcs_type: Option<AgentTraceVcsType>,
}

#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum AgentTraceVcsType {
Git,
Jj,
Hg,
Svn,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct AgentTraceVcs {
#[serde(rename = "type")]
pub kind: String,
pub r#type: AgentTraceVcsType,
pub revision: String,
}

Expand Down Expand Up @@ -217,7 +227,8 @@ pub struct AgentTrace {
#[serde(default)]
pub timestamp: String,
/// Version control metadata sourced from caller-provided commit metadata.
pub vcs: AgentTraceVcs,
#[serde(skip_serializing_if = "Option::is_none")]
pub vcs: Option<AgentTraceVcs>,
/// File-level trace entries, one per file present in `post_commit_patch`.
pub files: Vec<TraceFile>,
}
Expand Down Expand Up @@ -401,10 +412,10 @@ pub fn build_agent_trace(
version: default_agent_trace_version(),
id: generate_agent_trace_id(commit_time)?,
timestamp,
vcs: AgentTraceVcs {
kind: "git".to_owned(),
vcs: metadata.vcs_type.map(|vcs_type| AgentTraceVcs {
r#type: vcs_type,
revision: metadata.commit_revision.to_owned(),
},
}),
files,
})
}
Expand Down
15 changes: 11 additions & 4 deletions cli/src/services/agent_trace/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{
build_agent_trace, validate_agent_trace_value, AgentTraceMetadataInput, LineRange,
AGENT_TRACE_VERSION,
build_agent_trace, validate_agent_trace_value, AgentTraceMetadataInput, AgentTraceVcsType,
LineRange, AGENT_TRACE_VERSION,
};
use crate::services::patch::{combine_patches, parse_patch, ParsedPatch};
use serde_json::{json, Value};
Expand Down Expand Up @@ -62,13 +62,19 @@ fn assert_builds_expected_agent_trace(scenario: AgentTraceScenario) {
AgentTraceMetadataInput {
commit_timestamp: TEST_COMMIT_TIMESTAMP,
commit_revision: TEST_COMMIT_REVISION,
vcs_type: Some(AgentTraceVcsType::Git),
},
)
.expect("agent trace should build");
assert_eq!(actual.version, AGENT_TRACE_VERSION);
assert_eq!(actual.timestamp, TEST_COMMIT_TIMESTAMP);
assert_eq!(actual.vcs.kind, "git");
assert_eq!(actual.vcs.revision, TEST_COMMIT_REVISION);
assert_eq!(
actual.vcs,
Some(super::AgentTraceVcs {
r#type: AgentTraceVcsType::Git,
revision: TEST_COMMIT_REVISION.to_string(),
})
);
let actual_json = serde_json::to_value(&actual).expect("agent trace should serialize");
validate_agent_trace_value(&actual_json).expect("actual json should validate against schema");
assert_eq!(actual_json["vcs"], golden["vcs"]);
Expand Down Expand Up @@ -146,6 +152,7 @@ fn poem_edit_reconstruction_maps_each_hunk_to_one_range() {
AgentTraceMetadataInput {
commit_timestamp: TEST_COMMIT_TIMESTAMP,
commit_revision: TEST_COMMIT_REVISION,
vcs_type: Some(AgentTraceVcsType::Git),
},
)
.expect("agent trace should build");
Expand Down
39 changes: 29 additions & 10 deletions cli/src/services/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use serde_json::{json, to_string as serialize_to_json, Value};

use crate::services::agent_trace::{
build_agent_trace, validate_agent_trace_value, AgentTrace, AgentTraceMetadataInput,
AgentTraceVcsType,
};
use crate::services::agent_trace_db::{
AgentTraceDb, AgentTraceInsert, DiffTraceInsert, PostCommitPatchIntersectionInsert,
Expand All @@ -36,7 +37,7 @@ const MAX_TRACE_FILE_CREATE_ATTEMPTS: u64 = 1_000_000;
pub enum HookSubcommand {
PreCommit,
CommitMsg { message_file: PathBuf },
PostCommit,
PostCommit { vcs_type: Option<AgentTraceVcsType> },
PostRewrite { rewrite_method: String },
DiffTrace,
}
Expand Down Expand Up @@ -74,7 +75,9 @@ fn run_hooks_subcommand_in_repo(
HookSubcommand::CommitMsg { message_file } => {
run_commit_msg_subcommand_with_trace(repository_root, subcommand, message_file)
}
HookSubcommand::PostCommit => run_post_commit_subcommand_with_trace(repository_root),
HookSubcommand::PostCommit { vcs_type } => {
run_post_commit_subcommand_with_trace(repository_root, *vcs_type)
}
HookSubcommand::PostRewrite { rewrite_method } => {
run_post_rewrite_subcommand_with_trace(repository_root, subcommand, rewrite_method)
}
Expand Down Expand Up @@ -439,25 +442,34 @@ fn run_commit_msg_subcommand_with_trace(
run_commit_msg_subcommand_in_repo(repository_root, message_file)
}

fn run_post_commit_subcommand(repository_root: &Path) -> Result<String> {
fn run_post_commit_subcommand(
repository_root: &Path,
vcs_type: Option<AgentTraceVcsType>,
) -> Result<String> {
run_post_commit_subcommand_with(
repository_root,
vcs_type,
run_post_commit_intersection_flow,
run_post_commit_agent_trace_flow,
)
}

fn run_post_commit_subcommand_with<F, B>(
repository_root: &Path,
vcs_type: Option<AgentTraceVcsType>,
run_intersection_flow: F,
run_agent_trace_flow: B,
) -> Result<String>
where
F: FnOnce(&Path) -> Result<PostCommitIntersectionFlowResult>,
B: FnOnce(&Path, &PostCommitIntersectionFlowResult) -> Result<AgentTrace>,
B: FnOnce(
&Path,
&PostCommitIntersectionFlowResult,
Option<AgentTraceVcsType>,
) -> Result<AgentTrace>,
{
let result = run_intersection_flow(repository_root)?;
let _agent_trace = run_agent_trace_flow(repository_root, &result)?;
let _agent_trace = run_agent_trace_flow(repository_root, &result, vcs_type)?;

Ok(format!(
"post-commit hook processed intersection: commit={}, intersection_files={}",
Expand All @@ -469,11 +481,13 @@ where
fn run_post_commit_agent_trace_flow(
_repository_root: &Path,
flow_result: &PostCommitIntersectionFlowResult,
vcs_type: Option<AgentTraceVcsType>,
) -> Result<AgentTrace> {
let db = AgentTraceDb::new().context("Failed to open Agent Trace DB for post-commit trace.")?;

run_post_commit_agent_trace_flow_with(
flow_result,
vcs_type,
|trace_value| {
validate_agent_trace_value(trace_value)
.map_err(|error| anyhow!(error.to_string()))
Expand All @@ -492,6 +506,7 @@ fn run_post_commit_agent_trace_flow(

fn run_post_commit_agent_trace_flow_with<V, I>(
flow_result: &PostCommitIntersectionFlowResult,
vcs_type: Option<AgentTraceVcsType>,
validate_agent_trace: V,
persist_agent_trace: I,
) -> Result<AgentTrace>
Expand All @@ -515,6 +530,7 @@ where
AgentTraceMetadataInput {
commit_timestamp: &commit_timestamp,
commit_revision: &flow_result.post_commit_data.commit_oid,
vcs_type,
},
)
.context("Failed to build Agent Trace payload from post-commit intersection flow result.")?;
Expand Down Expand Up @@ -629,10 +645,13 @@ fn current_unix_time_ms() -> Result<i64> {
.context("Current time exceeds i64 range for post-commit intersection.")
}

fn run_post_commit_subcommand_with_trace(repository_root: &Path) -> Result<String> {
let subcommand = HookSubcommand::PostCommit;
fn run_post_commit_subcommand_with_trace(
repository_root: &Path,
vcs_type: Option<AgentTraceVcsType>,
) -> Result<String> {
let subcommand = HookSubcommand::PostCommit { vcs_type };
let input = build_hook_trace_input_for_post_commit(repository_root);
let outcome = run_post_commit_subcommand(repository_root);
let outcome = run_post_commit_subcommand(repository_root, vcs_type);

let _ = persist_hook_trace(repository_root, &subcommand, &input, &outcome);

Expand Down Expand Up @@ -662,7 +681,7 @@ fn hook_runtime_invocation_name(subcommand: &HookSubcommand) -> &'static str {
match subcommand {
HookSubcommand::PreCommit => "pre-commit runtime invocation",
HookSubcommand::CommitMsg { .. } => "commit-msg runtime invocation",
HookSubcommand::PostCommit => "post-commit runtime invocation",
HookSubcommand::PostCommit { .. } => "post-commit runtime invocation",
HookSubcommand::PostRewrite { .. } => "post-rewrite runtime invocation",
HookSubcommand::DiffTrace => "diff-trace runtime invocation",
}
Expand Down Expand Up @@ -704,7 +723,7 @@ fn hook_trace_name(subcommand: &HookSubcommand) -> &'static str {
match subcommand {
HookSubcommand::PreCommit => "pre-commit",
HookSubcommand::CommitMsg { .. } => "commit-msg",
HookSubcommand::PostCommit => "post-commit",
HookSubcommand::PostCommit { .. } => "post-commit",
HookSubcommand::PostRewrite { .. } => "post-rewrite",
HookSubcommand::DiffTrace => "diff-trace",
}
Expand Down
27 changes: 25 additions & 2 deletions cli/src/services/parse/command_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,9 +384,12 @@ fn convert_hooks_subcommand(
subcommand: services::hooks::HookSubcommand::CommitMsg { message_file },
}))
}
cli_schema::HooksSubcommand::PostCommit => {
cli_schema::HooksSubcommand::PostCommit { vcs } => {
let vcs_type = parse_optional_hook_vcs_type(vcs.as_deref())
.map_err(ClassifiedError::validation)?;

Ok(Box::new(services::hooks::command::HooksCommand {
subcommand: services::hooks::HookSubcommand::PostCommit,
subcommand: services::hooks::HookSubcommand::PostCommit { vcs_type },
}))
}
cli_schema::HooksSubcommand::PostRewrite { rewrite_method } => {
Expand All @@ -401,3 +404,23 @@ fn convert_hooks_subcommand(
}
}
}

fn parse_optional_hook_vcs_type(
vcs: Option<&str>,
) -> Result<Option<services::agent_trace::AgentTraceVcsType>, String> {
let Some(vcs) = vcs else {
return Ok(None);
};

let normalized = vcs.trim().to_ascii_lowercase();

match normalized.as_str() {
"git" => Ok(Some(services::agent_trace::AgentTraceVcsType::Git)),
"jj" => Ok(Some(services::agent_trace::AgentTraceVcsType::Jj)),
"hg" => Ok(Some(services::agent_trace::AgentTraceVcsType::Hg)),
"svn" => Ok(Some(services::agent_trace::AgentTraceVcsType::Svn)),
_ => Err(format!(
"Unsupported value for '--vcs': '{vcs}'. Supported values: git, jj, hg, svn."
)),
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
4 changes: 2 additions & 2 deletions context/context-map.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading