Skip to content

Commit 6e59a59

Browse files
committed
refactor: update commit tracking and notification system
- Removed unused dependencies from Cargo.lock and updated Cargo.toml to reflect changes. - Modified commit fetching to return a structured result with total commits and position. - Enhanced Discord notification to include formatted commit information and total commits. - Updated models to support new commit response structure and improved author handling.
1 parent e123e8b commit 6e59a59

8 files changed

Lines changed: 90 additions & 433 deletions

File tree

Cargo.lock

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

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ edition = "2024"
77
chrono = { version = "0.4.41", features = ["serde"] }
88
env_logger = "0.11.8"
99
log = "0.4.27"
10-
regex = "1.11.1"
1110
reqwest = { version = "0.12.16", features = ["json"] }
12-
scraper = "0.23.1"
1311
serde = { version = "1.0.219", features = ["derive"] }
1412
serde_json = "1.0.140"
1513
tokio = { version = "1.45.1", features = ["full"] }

src/core/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ impl Default for Config {
9393
bot_avatar_url: "https://i.imgur.com/on47Qk9.png".to_string(),
9494
},
9595
monitoring: MonitoringConfig {
96-
commits_url: "https://commits.facepunch.com/r/rust_reboot".to_string(),
96+
commits_url: "https://commits.facepunch.com/?format=json".to_string(),
9797
check_interval_secs: 50,
9898
},
9999
appearance: AppearanceConfig {

src/core/tracker.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ impl CommitTracker {
3939
}
4040

4141
async fn check_for_new_commits(&mut self) -> Result<(), Box<dyn Error>> {
42-
let commit = self.scraper.fetch_latest_commit(&self.config.monitoring.commits_url).await?;
42+
let result = self.scraper.fetch_latest_commit(&self.config.monitoring.commits_url).await?;
43+
let commit = &result.commit;
4344

4445
if commit.id > self.last_commit_id {
4546
self.last_commit_id = commit.id;
4647

47-
info!("🆕 New commit #{} by {} - {}", commit.id, commit.author, commit.message);
48+
info!("🆕 New commit #{} by {} - {}", commit.id, commit.author(), commit.message);
4849

49-
self.notifier.send_commit_notification(&commit).await?;
50+
self.notifier.send_commit_notification(&result).await?;
5051

5152
info!("✅ Sent to Discord");
5253
}

src/models/commit.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,42 @@
1-
#[derive(Debug, Clone)]
1+
use serde::Deserialize;
2+
3+
#[derive(Debug, Clone, Deserialize)]
4+
pub struct CommitsResponse {
5+
pub total: u32,
6+
pub skip: u32,
7+
pub take: u32,
8+
pub results: Vec<CommitInfo>,
9+
}
10+
11+
#[derive(Debug, Clone, Deserialize)]
212
pub struct CommitInfo {
313
pub id: i32,
4-
pub author: String,
514
pub repo: String,
615
pub branch: String,
716
pub changeset: String,
17+
pub created: String,
18+
pub likes: u32,
19+
pub dislikes: u32,
820
pub message: String,
9-
pub avatar_url: String,
10-
pub link: String,
21+
pub user: CommitUser,
22+
}
23+
24+
#[derive(Debug, Clone, Deserialize)]
25+
pub struct CommitUser {
26+
pub name: String,
27+
pub avatar: String,
28+
}
29+
30+
impl CommitInfo {
31+
pub fn link(&self) -> String {
32+
format!("https://commits.facepunch.com/{}", self.id)
33+
}
34+
35+
pub fn avatar_url(&self) -> &str {
36+
&self.user.avatar
37+
}
38+
39+
pub fn author(&self) -> &str {
40+
&self.user.name
41+
}
1142
}

src/services/discord.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::core::Config;
2-
use crate::models::{CommitInfo, DiscordEmbed, EmbedData, EmbedAuthor, EmbedField, EmbedFooter};
2+
use crate::models::{DiscordEmbed, EmbedData, EmbedAuthor, EmbedField, EmbedFooter};
3+
use crate::services::scraper::CommitResult;
34
use chrono;
45
use std::error::Error;
56

@@ -16,8 +17,8 @@ impl DiscordNotifier {
1617
}
1718
}
1819

19-
pub async fn send_commit_notification(&self, commit: &CommitInfo) -> Result<(), Box<dyn Error>> {
20-
let embed = self.build_embed(commit);
20+
pub async fn send_commit_notification(&self, result: &CommitResult) -> Result<(), Box<dyn Error>> {
21+
let embed = self.build_embed(result);
2122

2223
let response = self.client
2324
.post(&self.config.discord.webhook_url)
@@ -33,16 +34,18 @@ impl DiscordNotifier {
3334
Ok(())
3435
}
3536

36-
fn build_embed(&self, commit: &CommitInfo) -> DiscordEmbed {
37+
fn build_embed(&self, result: &CommitResult) -> DiscordEmbed {
38+
let commit = &result.commit;
39+
3740
DiscordEmbed {
3841
embeds: vec![EmbedData {
3942
title: "🔧 New Rust Commit".to_string(),
4043
description: format!("```\n{}\n```", commit.message),
4144
color: self.config.rust_color(),
4245
author: EmbedAuthor {
43-
name: commit.author.clone(),
46+
name: commit.author().to_string(),
4447
url: self.config.monitoring.commits_url.clone(),
45-
icon_url: commit.avatar_url.clone(),
48+
icon_url: commit.avatar_url().to_string(),
4649
},
4750
fields: vec![
4851
EmbedField {
@@ -57,16 +60,36 @@ impl DiscordNotifier {
5760
},
5861
EmbedField {
5962
name: "🔗 Changeset".to_string(),
60-
value: format!("[`{}`]({})", commit.changeset, commit.link),
63+
value: format!("[`{}`]({})", commit.changeset, commit.link()),
6164
inline: true,
6265
},
6366
],
6467
footer: EmbedFooter {
65-
text: self.config.discord.bot_name.clone(),
68+
text: format!("{} • Commit {} of {}",
69+
self.config.discord.bot_name,
70+
self.format_number(result.total_commits - result.position + 1),
71+
self.format_number(result.total_commits)
72+
),
6673
icon_url: self.config.discord.bot_avatar_url.clone(),
6774
},
6875
timestamp: chrono::Utc::now().to_rfc3339(),
6976
}],
7077
}
7178
}
79+
80+
fn format_number(&self, num: u32) -> String {
81+
// Add commas to large numbers for readability
82+
let num_str = num.to_string();
83+
let chars: Vec<char> = num_str.chars().collect();
84+
let mut result = String::new();
85+
86+
for (i, &ch) in chars.iter().enumerate() {
87+
if i > 0 && (chars.len() - i) % 3 == 0 {
88+
result.push(',');
89+
}
90+
result.push(ch);
91+
}
92+
93+
result
94+
}
7295
}

src/services/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub mod scraper;
22
pub mod discord;
33

4-
pub use scraper::*;
4+
pub use scraper::{CommitScraper, CommitResult};
55
pub use discord::*;

src/services/scraper.rs

Lines changed: 18 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,38 @@
1-
use crate::models::CommitInfo;
2-
use regex::Regex;
3-
use scraper::{Html, Selector};
1+
use crate::models::{CommitInfo, CommitsResponse};
42
use std::error::Error;
53

64
pub struct CommitScraper {
75
client: reqwest::Client,
86
}
97

8+
#[derive(Debug)]
9+
pub struct CommitResult {
10+
pub commit: CommitInfo,
11+
pub total_commits: u32,
12+
pub position: u32, // Position in the list (1 = latest)
13+
}
14+
1015
impl CommitScraper {
1116
pub fn new() -> Self {
1217
Self {
1318
client: reqwest::Client::new(),
1419
}
1520
}
1621

17-
pub async fn fetch_latest_commit(&self, url: &str) -> Result<CommitInfo, Box<dyn Error>> {
22+
pub async fn fetch_latest_commit(&self, url: &str) -> Result<CommitResult, Box<dyn Error>> {
1823
let response = self.client.get(url).send().await?;
19-
let html_content = response.text().await?;
20-
let document = Html::parse_document(&html_content);
21-
22-
self.parse_commit_from_html(&document)
23-
}
24-
25-
fn parse_commit_from_html(&self, document: &Html) -> Result<CommitInfo, Box<dyn Error>> {
26-
let commit_selector = Selector::parse("div.commit.columns")?;
27-
let commit = document
28-
.select(&commit_selector)
29-
.next()
30-
.ok_or("No commit found")?;
31-
32-
// Extract commit ID
33-
let like_id = commit
34-
.value()
35-
.attr("like-id")
36-
.ok_or("No like-id attribute found")?;
37-
let id: i32 = like_id.parse()?;
38-
39-
// Extract author
40-
let author_selector = Selector::parse("div.author")?;
41-
let author = commit
42-
.select(&author_selector)
43-
.next()
44-
.ok_or("No author found")?
45-
.text()
46-
.collect::<String>()
47-
.trim()
48-
.to_string();
24+
let commits_response: CommitsResponse = response.json().await?;
4925

50-
// Extract repo
51-
let repo_selector = Selector::parse("span.repo")?;
52-
let repo = commit
53-
.select(&repo_selector)
26+
let commit = commits_response
27+
.results
28+
.into_iter()
5429
.next()
55-
.ok_or("No repo found")?
56-
.text()
57-
.collect::<String>()
58-
.trim()
59-
.to_string();
60-
61-
// Extract branch
62-
let branch_selector = Selector::parse("span.branch")?;
63-
let branch = commit
64-
.select(&branch_selector)
65-
.next()
66-
.ok_or("No branch found")?
67-
.text()
68-
.collect::<String>()
69-
.trim()
70-
.to_string();
71-
72-
// Extract changeset
73-
let changeset_selector = Selector::parse("span.changeset")?;
74-
let changeset = commit
75-
.select(&changeset_selector)
76-
.next()
77-
.ok_or("No changeset found")?
78-
.text()
79-
.collect::<String>()
80-
.trim()
81-
.to_string();
82-
83-
// Extract commit message
84-
let message_selector = Selector::parse("div.commits-message")?;
85-
let message = commit
86-
.select(&message_selector)
87-
.next()
88-
.ok_or("No commit message found")?
89-
.text()
90-
.collect::<String>()
91-
.trim()
92-
.to_string();
93-
94-
// Extract avatar URL
95-
let avatar_selector = Selector::parse("div.avatar")?;
96-
let avatar_element = commit
97-
.select(&avatar_selector)
98-
.next()
99-
.ok_or("No avatar found")?;
100-
101-
let avatar_html = avatar_element.html();
102-
let url_regex = Regex::new(r"(https?://[^\s]+)")?;
103-
let avatar_url = url_regex
104-
.find(&avatar_html)
105-
.ok_or("No URL found in avatar")?
106-
.as_str()
107-
.trim_end_matches("');")
108-
.to_string();
109-
110-
// Build commit link
111-
let link = format!("https://commits.facepunch.com/{}", id);
30+
.ok_or("No commits found in response")?;
11231

113-
Ok(CommitInfo {
114-
id,
115-
author,
116-
repo,
117-
branch,
118-
changeset,
119-
message,
120-
avatar_url,
121-
link,
32+
Ok(CommitResult {
33+
commit,
34+
total_commits: commits_response.total,
35+
position: 1, // Latest commit is always position 1
12236
})
12337
}
12438
}

0 commit comments

Comments
 (0)