Skip to content

Commit 69385df

Browse files
authored
feat(telemetry): send repo_hash and commits_count in events (#178)
* feat(telemetry): add repo_hash and commits_count to event payload * feat(telemetry): pass repo_hash and commits_count from all call sites
1 parent c4ff261 commit 69385df

5 files changed

Lines changed: 127 additions & 12 deletions

File tree

‎Cargo.lock‎

Lines changed: 79 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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ clap = { version = "4", features = ["derive", "env"], optional = true }
4545
colored = { version = "3", optional = true }
4646
git2 = { version = "0.20", features = ["vendored-libgit2", "vendored-openssl"], optional = true }
4747
ureq = { version = "3", features = ["json"], optional = true }
48+
sha2 = "0.11.0"
49+
hex = "0.4.3"
4850

4951
[dev-dependencies]
5052
cargo-husky = { version = "1", default-features = false, features = ["user-hooks"] }

‎src/config.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ pub fn init(format: Option<ConfigFileFormat>) -> Result<()> {
728728
println!("Run: ferrflow check");
729729

730730
if config.workspace.telemetry {
731-
telemetry::send_event(telemetry::EventType::Init, None, None, None);
731+
telemetry::send_event(telemetry::EventType::Init, None, None, None, None);
732732
}
733733

734734
Ok(())

‎src/monorepo.rs‎

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub fn check(config_path: Option<&Path>, verbose: bool) -> Result<()> {
2828
let result = run_release_logic(&root, &config, true, verbose);
2929

3030
if config.workspace.telemetry {
31-
telemetry::send_event(telemetry::EventType::Check, None, None, None);
31+
telemetry::send_event(telemetry::EventType::Check, None, None, None, None);
3232
}
3333

3434
result
@@ -79,8 +79,8 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
7979

8080
let mut any_bumped = false;
8181
let mut files_to_commit: Vec<String> = Vec::new();
82-
// (tag_name, tag_msg, body, pkg_name, version)
83-
let mut tags_to_create: Vec<(String, String, String, String, String)> = Vec::new();
82+
// (tag_name, tag_msg, body, pkg_name, version, commits_count)
83+
let mut tags_to_create: Vec<(String, String, String, String, String, i32)> = Vec::new();
8484
let mut hook_contexts: Vec<(HookContext, usize)> = Vec::new(); // (ctx, pkg_index)
8585

8686
for (pkg_idx, pkg) in config.packages.iter().enumerate() {
@@ -280,6 +280,7 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
280280
Some(&pkg.name),
281281
Some(&new_version),
282282
None,
283+
Some(commits.len() as i32),
283284
);
284285
}
285286

@@ -290,6 +291,7 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
290291
body,
291292
pkg.name.clone(),
292293
new_version.clone(),
294+
commits.len() as i32,
293295
));
294296
}
295297

@@ -327,7 +329,7 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
327329
// Build the release commit message.
328330
let release_parts: Vec<String> = tags_to_create
329331
.iter()
330-
.map(|(_, _, _, name, ver)| format!("{name} v{ver}"))
332+
.map(|(_, _, _, name, ver, _)| format!("{name} v{ver}"))
331333
.collect();
332334
let skip_ci = if config.workspace.effective_skip_ci() {
333335
" [skip ci]"
@@ -362,7 +364,7 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
362364
"Automated release commit.\n\n{}",
363365
tags_to_create
364366
.iter()
365-
.map(|(tag, _, _, _, _)| format!("- `{tag}`"))
367+
.map(|(tag, _, _, _, _, _)| format!("- `{tag}`"))
366368
.collect::<Vec<_>>()
367369
.join("\n")
368370
);
@@ -400,7 +402,7 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
400402
}
401403

402404
// Tags are always created on the current HEAD.
403-
for (tag_name, tag_msg, _, _, _) in &tags_to_create {
405+
for (tag_name, tag_msg, _, _, _, _) in &tags_to_create {
404406
create_tag(&repo, tag_name, tag_msg)?;
405407
println!(" ✓ Created tag {}", tag_name.cyan());
406408
}
@@ -429,7 +431,7 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
429431
// Push tags (and branch for commit mode).
430432
let tag_refs: Vec<&str> = tags_to_create
431433
.iter()
432-
.map(|(t, _, _, _, _)| t.as_str())
434+
.map(|(t, _, _, _, _, _)| t.as_str())
433435
.collect();
434436
match mode {
435437
ReleaseCommitMode::Commit => {
@@ -458,20 +460,21 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
458460
}
459461

460462
if config.workspace.telemetry {
461-
for (_, _, _, pkg_name, version) in &tags_to_create {
463+
for (_, _, _, pkg_name, version, commit_count) in &tags_to_create {
462464
telemetry::send_event(
463465
telemetry::EventType::Release,
464466
Some(pkg_name),
465467
Some(version),
466468
None,
469+
Some(*commit_count),
467470
);
468471
}
469472
}
470473

471474
if let Ok(token) = std::env::var("GITHUB_TOKEN")
472475
&& let Some(slug) = get_repo_slug(&repo, &config.workspace.remote)
473476
{
474-
for (tag_name, _, body, _, _) in &tags_to_create {
477+
for (tag_name, _, body, _, _, _) in &tags_to_create {
475478
match create_github_release(&token, &slug, tag_name, body) {
476479
Ok(()) => println!(" ✓ GitHub Release {}", tag_name.cyan()),
477480
Err(err) => eprintln!(
@@ -493,7 +496,7 @@ fn run_release_logic(root: &Path, config: &Config, dry_run: bool, verbose: bool)
493496
.open(&summary_path)
494497
{
495498
let _ = writeln!(file, "## Released\n");
496-
for (tag_name, _, body, _, _) in &tags_to_create {
499+
for (tag_name, _, body, _, _, _) in &tags_to_create {
497500
let _ = writeln!(file, "### {tag_name}\n");
498501
let _ = writeln!(file, "{body}");
499502
}

‎src/telemetry.rs‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use serde::Serialize;
2+
use sha2::Digest;
23

34
const DEFAULT_API_URL: &str = "https://api.ferrflow.com";
45

@@ -22,6 +23,10 @@ struct EventPayload {
2223
package_version: Option<String>,
2324
#[serde(skip_serializing_if = "Option::is_none")]
2425
metadata: Option<serde_json::Value>,
26+
#[serde(skip_serializing_if = "Option::is_none")]
27+
repo_hash: Option<String>,
28+
#[serde(skip_serializing_if = "Option::is_none")]
29+
commits_count: Option<i32>,
2530
}
2631

2732
fn is_enabled() -> bool {
@@ -39,11 +44,28 @@ fn api_url() -> String {
3944
std::env::var("FERRFLOW_API_URL").unwrap_or_else(|_| DEFAULT_API_URL.to_string())
4045
}
4146

47+
fn get_repo_hash() -> Option<String> {
48+
let output = std::process::Command::new("git")
49+
.args(["remote", "get-url", "origin"])
50+
.output()
51+
.ok()?;
52+
if !output.status.success() {
53+
return None;
54+
}
55+
let url = String::from_utf8(output.stdout).ok()?.trim().to_string();
56+
if url.is_empty() {
57+
return None;
58+
}
59+
let hash = sha2::Sha256::digest(url.as_bytes());
60+
Some(hex::encode(hash))
61+
}
62+
4263
pub fn send_event(
4364
event_type: EventType,
4465
package_name: Option<&str>,
4566
package_version: Option<&str>,
4667
metadata: Option<serde_json::Value>,
68+
commits_count: Option<i32>,
4769
) {
4870
if !is_enabled() {
4971
return;
@@ -54,6 +76,8 @@ pub fn send_event(
5476
package_name: package_name.map(String::from),
5577
package_version: package_version.map(String::from),
5678
metadata,
79+
repo_hash: get_repo_hash(),
80+
commits_count,
5781
};
5882

5983
let url = format!("{}/events", api_url());
@@ -99,11 +123,15 @@ mod tests {
99123
package_name: None,
100124
package_version: None,
101125
metadata: None,
126+
repo_hash: None,
127+
commits_count: None,
102128
};
103129
let json = serde_json::to_value(&payload).unwrap();
104130
assert!(!json.as_object().unwrap().contains_key("package_name"));
105131
assert!(!json.as_object().unwrap().contains_key("package_version"));
106132
assert!(!json.as_object().unwrap().contains_key("metadata"));
133+
assert!(!json.as_object().unwrap().contains_key("repo_hash"));
134+
assert!(!json.as_object().unwrap().contains_key("commits_count"));
107135
}
108136

109137
#[test]
@@ -113,11 +141,15 @@ mod tests {
113141
package_name: Some("my-pkg".into()),
114142
package_version: Some("1.0.0".into()),
115143
metadata: None,
144+
repo_hash: Some("abc123".into()),
145+
commits_count: Some(42),
116146
};
117147
let json = serde_json::to_value(&payload).unwrap();
118148
assert_eq!(json["event_type"], "release");
119149
assert_eq!(json["package_name"], "my-pkg");
120150
assert_eq!(json["package_version"], "1.0.0");
151+
assert_eq!(json["repo_hash"], "abc123");
152+
assert_eq!(json["commits_count"], 42);
121153
}
122154

123155
#[test]

0 commit comments

Comments
 (0)