Initial upload: GitPulse - Developer Productivity Analyzer CLI tool
Some checks failed
CI / release (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
2026-02-04 15:45:25 +00:00
parent f524159e72
commit 9562b3dd63

158
src/commands/export.rs Normal file
View File

@@ -0,0 +1,158 @@
use crate::cli::export::ExportArgs;
use crate::config::Config;
use crate::git::Repository;
use crate::models::AnalysisResult;
use anyhow::{Context, Result};
use std::path::PathBuf;
pub mod export_args {
use clap::{Args, Parser};
use std::path::PathBuf;
#[derive(Parser, Debug)]
pub struct ExportArgs {
#[arg(long, value_name = "FORMAT")]
#[arg(help = "Export format: json, csv")]
pub format: String,
#[arg(short, long, value_name = "PATH")]
#[arg(help = "Output file path")]
pub output: Option<PathBuf>,
#[arg(long)]
#[arg(help = "Include commit history")]
pub history: bool,
#[arg(long)]
#[arg(help = "Include refactoring data")]
pub refactor: bool,
}
}
pub use export_args::ExportArgs;
pub fn run(
repo_path: Option<PathBuf>,
args: ExportArgs,
config: &Config,
verbose: bool,
) -> Result<()> {
let repo = Repository::new(repo_path)?;
if verbose {
eprintln!("Exporting from repository at: {}", repo.path().display());
}
let result = crate::commands::analyze::run(
Some(repo.path().clone()),
crate::commands::analyze::AnalyzeArgs {
since: None,
until: None,
commits: None,
include_merges: false,
no_churn: false,
no_refactor: !args.refactor,
json: true,
history: args.history,
top: None,
output: None,
},
config,
verbose,
)?;
match args.format.to_lowercase().as_str() {
"json" | "j" => {
if let Some(output) = args.output {
export::export_json_to_file(&result, &output)?;
if verbose {
eprintln!("Exported to {}", output.display());
}
} else {
export::export_json(&result, None)?;
}
}
"csv" | "c" => {
if let Some(output) = args.output {
export::export_csv_to_file(&result, &output)?;
if verbose {
eprintln!("Exported to {}", output.display());
}
} else {
println!("CSV export requires an output file. Use --output <file.csv>");
}
}
_ => {
anyhow::bail!("Unsupported format: {}. Use 'json' or 'csv'.", args.format);
}
}
Ok(())
}
pub mod export {
use crate::models::AnalysisResult;
use anyhow::{Context, Result};
use serde_json;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
pub fn export_json(result: &AnalysisResult, output: Option<PathBuf>) -> Result<()> {
let json = serde_json::to_string_pretty(result)
.context("Failed to serialize to JSON")?;
if let Some(path) = output {
let mut file = File::create(&path).context("Failed to create output file")?;
file.write_all(json.as_bytes())
.context("Failed to write to output file")?;
} else {
println!("{}", json);
}
Ok(())
}
pub fn export_json_to_file(result: &AnalysisResult, path: &PathBuf) -> Result<()> {
export_json(result, Some(path.clone()))
}
pub fn export_csv(result: &AnalysisResult, _output: &PathBuf) -> Result<()> {
println!("Contributors CSV:");
println!("Name,Email,Commits,Lines Added,Lines Removed,Net Change");
for author in &result.contributors.top_contributors {
println!(
"{},{},{},{},{},{}",
author.name,
author.email,
author.commits,
author.lines_added,
author.lines_removed,
author.net_change
);
}
Ok(())
}
pub fn export_csv_to_file(result: &AnalysisResult, path: &PathBuf) -> Result<()> {
let mut wtr = csv::Writer::from_path(path).context("Failed to create CSV writer")?;
wtr.write_record(&[
"Name", "Email", "Commits", "Lines Added", "Lines Removed", "Net Change",
])?;
for author in &result.contributors.top_contributors {
wtr.write_record(&[
&author.name,
&author.email,
&author.commits.to_string(),
&author.lines_added.to_string(),
&author.lines_removed.to_string(),
&author.net_change.to_string(),
])?;
}
wtr.flush()?;
Ok(())
}
}