Skip to content

Commit 017823a

Browse files
committed
🚨 Fix clippy lints across codebase
Fix clippy lints across codebase Replace println! with ui helper functions for consistent output handling and respect quiet mode throughout the application. Update all file analyzers to use multi-line regex formatting for better readability. Add missing std::fmt::Write imports and use write!/writeln! macros instead of string concatenation for better performance. Key changes: - Replace println! with ui::print_message, ui::print_newline, and ui::print_bordered_content functions - Import std::fmt::Write as FmtWrite to avoid naming conflicts - Use write!/writeln! macros instead of push_str for string building - Format multi-line regex patterns consistently across file analyzers - Replace once_cell lazy_static with std::sync::LazyLock - Update logger static variables to use consistent formatting Affected areas include UI output, string formatting, regex definitions, and static variable declarations across 33 files.
1 parent a6bbdae commit 017823a

33 files changed

+605
-449
lines changed

src/changes/changelog.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use anyhow::{Context, Result};
99
use chrono;
1010
use colored::Colorize;
1111
use regex;
12+
use std::fmt::Write as FmtWrite;
1213
use std::fs;
1314
use std::io::Write;
1415
use std::path::Path;
@@ -244,7 +245,8 @@ fn format_changelog_response(response: &ChangelogResponse) -> String {
244245
.clone()
245246
.unwrap_or_else(|| "Unreleased".to_string());
246247

247-
formatted.push_str(&format!("## [{}] - \n\n", version.bright_green().bold()));
248+
write!(formatted, "## [{}] - \n\n", version.bright_green().bold())
249+
.expect("writing to string should never fail");
248250

249251
// Define the order of change types
250252
let ordered_types = [
@@ -308,17 +310,21 @@ fn format_change_entry(entry: &ChangeEntry) -> String {
308310
let mut formatted = format!("- {}", entry.description);
309311

310312
if !entry.associated_issues.is_empty() {
311-
formatted.push_str(&format!(
313+
write!(
314+
formatted,
312315
" ({})",
313316
entry.associated_issues.join(", ").yellow()
314-
));
317+
)
318+
.expect("writing to string should never fail");
315319
}
316320

317321
if let Some(pr) = &entry.pull_request {
318-
formatted.push_str(&format!(" [{}]", pr.bright_purple()));
322+
write!(formatted, " [{}]", pr.bright_purple())
323+
.expect("writing to string should never fail");
319324
}
320325

321-
formatted.push_str(&format!(" ({})\n", entry.commit_hashes.join(", ").dimmed()));
326+
writeln!(formatted, " ({})", entry.commit_hashes.join(", ").dimmed())
327+
.expect("writing to string should never fail");
322328

323329
formatted
324330
}

src/changes/cli.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,8 @@ pub async fn handle_changelog_command(
8484
// Clear the spinner and display the result
8585
spinner.finish_and_clear();
8686

87-
println!("{}", "━".repeat(50).bright_purple());
88-
println!("{}", &changelog);
89-
println!("{}", "━".repeat(50).bright_purple());
87+
// Output the changelog with decorative borders
88+
ui::print_bordered_content(&changelog);
9089

9190
// Update the changelog file if requested
9291
if update_file {
@@ -185,9 +184,8 @@ pub async fn handle_release_notes_command(
185184
// Clear the spinner and display the result
186185
spinner.finish_and_clear();
187186

188-
println!("{}", "━".repeat(50).bright_purple());
189-
println!("{}", &release_notes);
190-
println!("{}", "━".repeat(50).bright_purple());
187+
// Output the release notes with decorative borders
188+
ui::print_bordered_content(&release_notes);
191189

192190
Ok(())
193191
}

src/changes/prompt.rs

Lines changed: 103 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::common::{DetailLevel, get_combined_instructions};
66
use crate::config::Config;
77
use crate::gitmoji::get_gitmoji_list;
88
use crate::log_debug;
9+
use std::fmt::Write;
910

1011
pub fn create_changelog_system_prompt(config: &Config) -> String {
1112
let changelog_schema = schemars::schema_for!(ChangelogResponse);
@@ -234,90 +235,115 @@ pub fn create_release_notes_system_prompt(config: &Config) -> String {
234235
prompt
235236
}
236237

237-
pub fn create_changelog_user_prompt(
238-
changes: &[AnalyzedChange],
239-
total_metrics: &ChangeMetrics,
240-
detail_level: DetailLevel,
241-
from: &str,
242-
to: &str,
243-
readme_summary: Option<&str>,
244-
) -> String {
245-
let mut prompt =
246-
format!("Based on the following changes from {from} to {to}, generate a changelog:\n\n");
247-
238+
/// Common helper function to format metrics summary
239+
fn format_metrics_summary(prompt: &mut String, total_metrics: &ChangeMetrics) {
248240
prompt.push_str("Overall Changes:\n");
249-
prompt.push_str(&format!("Total commits: {}\n", total_metrics.total_commits));
250-
prompt.push_str(&format!("Files changed: {}\n", total_metrics.files_changed));
251-
prompt.push_str(&format!(
252-
"Total lines changed: {}\n",
241+
writeln!(prompt, "Total commits: {}", total_metrics.total_commits)
242+
.expect("writing to string should never fail");
243+
writeln!(prompt, "Files changed: {}", total_metrics.files_changed)
244+
.expect("writing to string should never fail");
245+
writeln!(
246+
prompt,
247+
"Total lines changed: {}",
253248
total_metrics.total_lines_changed
254-
));
255-
prompt.push_str(&format!("Insertions: {}\n", total_metrics.insertions));
256-
prompt.push_str(&format!("Deletions: {}\n\n", total_metrics.deletions));
249+
)
250+
.expect("writing to string should never fail");
251+
writeln!(prompt, "Insertions: {}", total_metrics.insertions)
252+
.expect("writing to string should never fail");
253+
write!(prompt, "Deletions: {}\n\n", total_metrics.deletions)
254+
.expect("writing to string should never fail");
255+
}
257256

258-
for change in changes {
259-
prompt.push_str(&format!("Commit: {}\n", change.commit_hash));
260-
prompt.push_str(&format!("Author: {}\n", change.author));
261-
prompt.push_str(&format!("Message: {}\n", change.commit_message));
262-
prompt.push_str(&format!("Type: {:?}\n", change.change_type));
263-
prompt.push_str(&format!("Breaking Change: {}\n", change.is_breaking_change));
264-
prompt.push_str(&format!(
265-
"Associated Issues: {}\n",
266-
change.associated_issues.join(", ")
267-
));
268-
if let Some(pr) = &change.pull_request {
269-
prompt.push_str(&format!("Pull Request: {pr}\n"));
270-
}
271-
prompt.push_str(&format!(
272-
"Files changed: {}\n",
273-
change.metrics.files_changed
274-
));
275-
prompt.push_str(&format!(
276-
"Lines changed: {}\n",
277-
change.metrics.total_lines_changed
278-
));
279-
prompt.push_str(&format!("Insertions: {}\n", change.metrics.insertions));
280-
prompt.push_str(&format!("Deletions: {}\n", change.metrics.deletions));
281-
prompt.push_str(&format!("Impact score: {:.2}\n", change.impact_score));
257+
/// Common helper function to format individual change details
258+
fn format_change_details(prompt: &mut String, change: &AnalyzedChange, detail_level: DetailLevel) {
259+
writeln!(prompt, "Commit: {}", change.commit_hash).expect("writing to string should never fail");
260+
writeln!(prompt, "Author: {}", change.author).expect("writing to string should never fail");
261+
writeln!(prompt, "Message: {}", change.commit_message)
262+
.expect("writing to string should never fail");
263+
writeln!(prompt, "Type: {:?}", change.change_type).expect("writing to string should never fail");
264+
writeln!(prompt, "Breaking Change: {}", change.is_breaking_change)
265+
.expect("writing to string should never fail");
266+
writeln!(
267+
prompt,
268+
"Associated Issues: {}",
269+
change.associated_issues.join(", ")
270+
)
271+
.expect("writing to string should never fail");
272+
273+
if let Some(pr) = &change.pull_request {
274+
writeln!(prompt, "Pull Request: {pr}").expect("writing to string should never fail");
275+
}
282276

283-
match detail_level {
284-
DetailLevel::Minimal => {
285-
// For minimal detail, we don't include file-level changes
286-
}
287-
DetailLevel::Standard | DetailLevel::Detailed => {
288-
prompt.push_str("File changes:\n");
289-
for file_change in &change.file_changes {
290-
prompt.push_str(&format!(
291-
" - {} ({:?})\n",
292-
file_change.new_path, file_change.change_type
293-
));
294-
if detail_level == DetailLevel::Detailed {
295-
for analysis in &file_change.analysis {
296-
prompt.push_str(&format!(" * {analysis}\n"));
297-
}
277+
writeln!(prompt, "Impact score: {:.2}", change.impact_score)
278+
.expect("writing to string should never fail");
279+
280+
format_file_changes(prompt, change, detail_level);
281+
prompt.push('\n');
282+
}
283+
284+
/// Helper function to format file changes based on detail level
285+
fn format_file_changes(prompt: &mut String, change: &AnalyzedChange, detail_level: DetailLevel) {
286+
match detail_level {
287+
DetailLevel::Minimal => {
288+
// For minimal detail, we don't include file-level changes
289+
}
290+
DetailLevel::Standard | DetailLevel::Detailed => {
291+
prompt.push_str("File changes:\n");
292+
for file_change in &change.file_changes {
293+
writeln!(
294+
prompt,
295+
" - {} ({:?})",
296+
file_change.new_path, file_change.change_type
297+
)
298+
.expect("writing to string should never fail");
299+
if detail_level == DetailLevel::Detailed {
300+
for analysis in &file_change.analysis {
301+
writeln!(prompt, " * {analysis}")
302+
.expect("writing to string should never fail");
298303
}
299304
}
300305
}
301306
}
302-
303-
prompt.push('\n');
304307
}
308+
}
305309

310+
/// Helper function to add readme summary if available
311+
fn add_readme_summary(prompt: &mut String, readme_summary: Option<&str>) {
306312
if let Some(summary) = readme_summary {
307313
prompt.push_str("\nProject README Summary:\n");
308314
prompt.push_str(summary);
309315
prompt.push_str("\n\n");
310316
}
317+
}
311318

312-
prompt.push_str(&format!("Please generate a {} changelog for the changes from {} to {}, adhering to the Keep a Changelog format. ",
319+
pub fn create_changelog_user_prompt(
320+
changes: &[AnalyzedChange],
321+
total_metrics: &ChangeMetrics,
322+
detail_level: DetailLevel,
323+
from: &str,
324+
to: &str,
325+
readme_summary: Option<&str>,
326+
) -> String {
327+
let mut prompt =
328+
format!("Based on the following changes from {from} to {to}, generate a changelog:\n\n");
329+
330+
format_metrics_summary(&mut prompt, total_metrics);
331+
332+
for change in changes {
333+
format_change_details(&mut prompt, change, detail_level);
334+
}
335+
336+
add_readme_summary(&mut prompt, readme_summary);
337+
338+
write!(&mut prompt, "Please generate a {} changelog for the changes from {} to {}, adhering to the Keep a Changelog format. ",
313339
match detail_level {
314340
DetailLevel::Minimal => "concise",
315341
DetailLevel::Standard => "comprehensive",
316342
DetailLevel::Detailed => "highly detailed",
317343
},
318344
from,
319345
to
320-
));
346+
).expect("writing to string should never fail");
321347

322348
prompt.push_str("Categorize the changes appropriately and focus on the most significant updates and their impact on the project. ");
323349
prompt.push_str("For each change, provide a clear description of what was changed, adhering to the guidelines in the system prompt. ");
@@ -342,61 +368,16 @@ pub fn create_release_notes_user_prompt(
342368
let mut prompt =
343369
format!("Based on the following changes from {from} to {to}, generate release notes:\n\n");
344370

345-
prompt.push_str("Overall Changes:\n");
346-
prompt.push_str(&format!("Total commits: {}\n", changes.len()));
347-
prompt.push_str(&format!("Files changed: {}\n", total_metrics.files_changed));
348-
prompt.push_str(&format!(
349-
"Total lines changed: {}\n",
350-
total_metrics.total_lines_changed
351-
));
352-
prompt.push_str(&format!("Insertions: {}\n", total_metrics.insertions));
353-
prompt.push_str(&format!("Deletions: {}\n\n", total_metrics.deletions));
371+
format_metrics_summary(&mut prompt, total_metrics);
354372

355373
for change in changes {
356-
prompt.push_str(&format!("Commit: {}\n", change.commit_hash));
357-
prompt.push_str(&format!("Author: {}\n", change.author));
358-
prompt.push_str(&format!("Message: {}\n", change.commit_message));
359-
prompt.push_str(&format!("Type: {:?}\n", change.change_type));
360-
prompt.push_str(&format!("Breaking Change: {}\n", change.is_breaking_change));
361-
prompt.push_str(&format!(
362-
"Associated Issues: {}\n",
363-
change.associated_issues.join(", ")
364-
));
365-
if let Some(pr) = &change.pull_request {
366-
prompt.push_str(&format!("Pull Request: {pr}\n"));
367-
}
368-
prompt.push_str(&format!("Impact score: {:.2}\n", change.impact_score));
369-
370-
match detail_level {
371-
DetailLevel::Minimal => {
372-
// For minimal detail, we don't include file-level changes
373-
}
374-
DetailLevel::Standard | DetailLevel::Detailed => {
375-
prompt.push_str("File changes:\n");
376-
for file_change in &change.file_changes {
377-
prompt.push_str(&format!(
378-
" - {} ({:?})\n",
379-
file_change.new_path, file_change.change_type
380-
));
381-
if detail_level == DetailLevel::Detailed {
382-
for analysis in &file_change.analysis {
383-
prompt.push_str(&format!(" * {analysis}\n"));
384-
}
385-
}
386-
}
387-
}
388-
}
389-
390-
prompt.push('\n');
374+
format_change_details(&mut prompt, change, detail_level);
391375
}
392376

393-
if let Some(summary) = readme_summary {
394-
prompt.push_str("\nProject README Summary:\n");
395-
prompt.push_str(summary);
396-
prompt.push_str("\n\n");
397-
}
377+
add_readme_summary(&mut prompt, readme_summary);
398378

399-
prompt.push_str(&format!(
379+
write!(
380+
&mut prompt,
400381
"Please generate {} release notes for the changes from {} to {}. ",
401382
match detail_level {
402383
DetailLevel::Minimal => "concise",
@@ -405,37 +386,31 @@ pub fn create_release_notes_user_prompt(
405386
},
406387
from,
407388
to
408-
));
409-
410-
prompt.push_str("Focus on the impact and benefits of the changes to users and developers. ");
411-
prompt.push_str("Highlight key features, improvements, and fixes. ");
412-
prompt.push_str("Include a high-level summary of the release, major changes, and any breaking changes or important upgrade notes. ");
413-
prompt.push_str("Group changes into meaningful sections and explain the rationale behind important changes when possible. ");
414-
prompt.push_str("Include associated issue numbers and pull request numbers when relevant. ");
389+
)
390+
.expect("writing to string should never fail");
415391

416392
match detail_level {
417393
DetailLevel::Minimal => {
418394
prompt.push_str(
419-
"Keep the release notes brief and focused on the most significant changes. ",
395+
"Keep the release notes brief and focus only on the most critical changes. ",
420396
);
421397
}
422398
DetailLevel::Standard => {
423-
prompt.push_str("Provide a balanced overview of all important changes, with some details on major features or fixes. ");
399+
prompt.push_str("Provide a balanced overview of all significant changes. ");
424400
}
425401
DetailLevel::Detailed => {
426-
prompt.push_str("Include detailed explanations of changes, their rationale, and potential impact on the project or workflow. ");
427-
prompt.push_str("Provide context for technical changes and include file-level details where relevant. ");
402+
prompt.push_str("Include detailed explanations and context for all changes. ");
428403
}
429404
}
430405

406+
prompt.push_str("Focus on user-facing changes and highlight the most impactful improvements, new features, and bug fixes. ");
407+
prompt.push_str("Structure the notes to be clear and actionable for users and developers. ");
408+
prompt.push_str("Include upgrade notes for any breaking changes. ");
409+
prompt.push_str("Reference associated issues and pull requests where relevant. ");
410+
431411
if readme_summary.is_some() {
432-
prompt.push_str("Ensure the release notes align with the project's overall goals and main features as described in the README summary. ");
412+
prompt.push_str("Use the README summary to understand the project context and ensure the release notes align with the project's purpose and user base. ");
433413
}
434414

435-
prompt.push_str(
436-
"Incorporate the overall metrics to give context about the scope of this release. ",
437-
);
438-
prompt.push_str("Pay special attention to changes with high impact scores, as they are likely to be the most significant. ");
439-
440415
prompt
441416
}

0 commit comments

Comments
 (0)