From 3a27e6f7c103a477efb03d061e7b42948d7a63c3 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:37:13 -0400 Subject: [PATCH 01/16] changes from claude --- .github/workflows/pr-comment.yml | 42 ++++++++ src/commands/blame.rs | 4 +- src/commands/mod.rs | 2 + src/commands/stats.rs | 178 +++++++++++++++++++++++++++++++ src/main.rs | 9 ++ 5 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/pr-comment.yml create mode 100644 src/commands/stats.rs diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml new file mode 100644 index 000000000..bd5bec82f --- /dev/null +++ b/.github/workflows/pr-comment.yml @@ -0,0 +1,42 @@ +name: PR Comment on Merge + +on: + pull_request: + types: [closed] + +jobs: + comment-on-merge: + name: Comment on Merged PR + runs-on: ubuntu-latest + if: github.event.pull_request.merged == true + + steps: + - name: Comment on merged PR + uses: actions/github-script@v7 + with: + script: | + const { owner, repo, number } = context.issue; + + const comment = `🎉 **PR Merged Successfully!** + + This pull request has been merged into the main branch. Thank you for your contribution! + + **Merge Commit:** \`${context.payload.pull_request.merge_commit_sha}\` + + **Merge Details:** + - Merged by: @${context.payload.pull_request.merged_by.login} + - Merged at: ${new Date(context.payload.pull_request.merged_at).toLocaleString()} + + **Next Steps:** + - The changes are now live in the main branch + - If this was a feature or bug fix, consider updating the documentation + - If you have any follow-up tasks, please create new issues or PRs + + Thanks again for contributing to the project! 🚀`; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body: comment + }); diff --git a/src/commands/blame.rs b/src/commands/blame.rs index 792251646..09b612d06 100644 --- a/src/commands/blame.rs +++ b/src/commands/blame.rs @@ -107,7 +107,7 @@ pub fn run( Ok(line_authors) } -fn get_git_blame_hunks( +pub fn get_git_blame_hunks( repo: &Repository, file_path: &str, start_line: u32, @@ -149,7 +149,7 @@ fn get_git_blame_hunks( Ok(hunks) } -fn overlay_ai_authorship( +pub fn overlay_ai_authorship( repo: &Repository, blame_hunks: &[BlameHunk], file_path: &str, diff --git a/src/commands/mod.rs b/src/commands/mod.rs index c4e9f79b4..734061617 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -3,8 +3,10 @@ pub mod checkpoint; pub mod init; pub mod post_commit; pub mod pre_commit; +pub mod stats; pub use blame::run as blame; pub use checkpoint::run as checkpoint; pub use init::run as init; pub use post_commit::run as post_commit; pub use pre_commit::run as pre_commit; +pub use stats::run as stats; diff --git a/src/commands/stats.rs b/src/commands/stats.rs new file mode 100644 index 000000000..d316d8cf9 --- /dev/null +++ b/src/commands/stats.rs @@ -0,0 +1,178 @@ +use crate::commands::blame::{get_git_blame_hunks, overlay_ai_authorship}; +use crate::error::GitAiError; +use crate::git::refs::get_reference_as_authorship_log; +use crate::log_fmt::authorship_log::AuthorshipLog; +use git2::{DiffOptions, Repository}; +use std::collections::HashMap; + +#[derive(Debug, Clone)] +pub struct FileStats { + pub additions: HashMap, + pub deletions: u32, + pub total_additions: u32, +} + +pub fn run(repo: &Repository, sha: &str) -> Result<(), GitAiError> { + // Find the commit + let commit = repo.find_commit(repo.revparse_single(sha)?.id())?; + + // Get the parent commit (for diff) + let parent = if let Ok(parent) = commit.parent(0) { + parent + } else { + return Err(GitAiError::Generic("Commit has no parent".to_string())); + }; + + // Get the diff between parent and commit + let tree = commit.tree()?; + let parent_tree = parent.tree()?; + + let mut diff_opts = DiffOptions::new(); + diff_opts.context_lines(0); // No context lines + + let diff = repo.diff_tree_to_tree(Some(&parent_tree), Some(&tree), Some(&mut diff_opts))?; + + // Process the diff and collect statistics + let mut file_stats = HashMap::new(); + let mut total_additions_by_author = HashMap::new(); + let mut total_deletions = 0; + + // For each file, collect added and deleted lines + let mut file_added_lines: HashMap> = HashMap::new(); + let mut file_deleted_counts: HashMap = HashMap::new(); + + diff.foreach( + &mut |_delta, _| true, + None, + None, + Some(&mut |delta, _hunk, line| { + let file_path = delta + .new_file() + .path() + .unwrap() + .to_string_lossy() + .to_string(); + match line.origin() { + '+' => { + let line_num = line.new_lineno().unwrap_or(0) as u32; + file_added_lines + .entry(file_path) + .or_default() + .push(line_num); + } + '-' => { + *file_deleted_counts.entry(file_path).or_default() += 1; + total_deletions += 1; + } + _ => {} + } + true + }), + )?; + + // For each file, use blame overlay logic to attribute added lines + for (file_path, added_lines) in file_added_lines.iter() { + // Get blame hunks for the file (for all lines, since we may not know the exact range) + let total_lines = { + // Try to get the file from the new tree + if let Ok(entry) = tree.get_path(std::path::Path::new(file_path)) { + if let Ok(blob) = repo.find_blob(entry.id()) { + let content = std::str::from_utf8(blob.content()).unwrap_or(""); + content.lines().count() as u32 + } else { + 0 + } + } else { + 0 + } + }; + if total_lines == 0 { + continue; + } + let blame_hunks = match get_git_blame_hunks(repo, file_path, 1, total_lines) { + Ok(hunks) => hunks, + Err(_) => continue, + }; + let line_authors = match overlay_ai_authorship(repo, &blame_hunks, file_path) { + Ok(authors) => authors, + Err(_) => continue, + }; + let stats = file_stats.entry(file_path.clone()).or_insert(FileStats { + additions: HashMap::new(), + deletions: *file_deleted_counts.get(file_path).unwrap_or(&0), + total_additions: 0, + }); + for &line_num in added_lines { + let author = line_authors + .get(&line_num) + .cloned() + .unwrap_or("unknown".to_string()); + *stats.additions.entry(author.clone()).or_insert(0) += 1; + *total_additions_by_author.entry(author).or_insert(0) += 1; + stats.total_additions += 1; + } + } + // For files with only deletions + for (file_path, &del_count) in file_deleted_counts.iter() { + file_stats.entry(file_path.clone()).or_insert(FileStats { + additions: HashMap::new(), + deletions: del_count, + total_additions: 0, + }); + } + + // Print the statistics + print_stats(&file_stats, &total_additions_by_author, total_deletions); + + Ok(()) +} + +fn print_stats( + file_stats: &HashMap, + total_additions_by_author: &HashMap, + total_deletions: u32, +) { + // Find the maximum changes for scaling + let max_changes = file_stats + .values() + .map(|stats| stats.total_additions.max(stats.deletions)) + .max() + .unwrap_or(1); + + // Calculate scale factor (minimum 1, maximum 20 characters) + let scale_factor = (20.0 / max_changes as f64).min(1.0); + + println!("Statistics for commit:"); + println!("{}", "=".repeat(50)); + + // Print per-file statistics + for (file_path, stats) in file_stats.iter() { + print_file_stats(file_path, stats, scale_factor); + } + + // Print totals + println!("\nTotal Additions:"); + for (author, count) in total_additions_by_author.iter() { + println!(" {} {}", author, count); + } + + println!("\nTotal Deletions: {}", total_deletions); +} + +fn print_file_stats(file_path: &str, stats: &FileStats, scale_factor: f64) { + println!("\n{}", file_path); + + // Print additions by author + for (author, count) in stats.additions.iter() { + let bar_length = ((*count as f64 * scale_factor).round() as usize).max(1); + let bar = "+".repeat(bar_length); + println!(" {} {:>3} {}", bar, count, author); + } + + // Print deletions + if stats.deletions > 0 { + let bar_length = ((stats.deletions as f64 * scale_factor).round() as usize).max(1); + let bar = "-".repeat(bar_length); + println!(" {} {:>3}", bar, stats.deletions); + } +} diff --git a/src/main.rs b/src/main.rs index 6263dcd67..e9d1bfaa1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,11 @@ enum Commands { /// file to blame (can include line range like "file.rs:10-20") file: String, }, + /// show authorship statistics for a commit + Stats { + /// commit SHA to analyze (defaults to HEAD) + sha: Option, + }, PreCommit, PostCommit { /// force execution even if working directory is not clean @@ -102,6 +107,10 @@ fn main() { // Convert the blame result to unit result to match other commands commands::blame(&repo, &file_path, line_range).map(|_| ()) } + Commands::Stats { sha } => { + let sha = sha.as_deref().unwrap_or("HEAD"); + commands::stats(&repo, sha) + } Commands::PreCommit => commands::pre_commit(&repo, default_user_name), Commands::PostCommit { force } => { commands::post_commit(&repo, *force).unwrap(); From 221741113a186b1062f5cf5a2d81433d5e15cfb9 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:38:40 -0400 Subject: [PATCH 02/16] update format --- src/commands/stats.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/commands/stats.rs b/src/commands/stats.rs index d316d8cf9..560fc9a46 100644 --- a/src/commands/stats.rs +++ b/src/commands/stats.rs @@ -1,7 +1,5 @@ use crate::commands::blame::{get_git_blame_hunks, overlay_ai_authorship}; use crate::error::GitAiError; -use crate::git::refs::get_reference_as_authorship_log; -use crate::log_fmt::authorship_log::AuthorshipLog; use git2::{DiffOptions, Repository}; use std::collections::HashMap; @@ -166,7 +164,7 @@ fn print_file_stats(file_path: &str, stats: &FileStats, scale_factor: f64) { for (author, count) in stats.additions.iter() { let bar_length = ((*count as f64 * scale_factor).round() as usize).max(1); let bar = "+".repeat(bar_length); - println!(" {} {:>3} {}", bar, count, author); + println!(" {} {} {:>3}", author, bar, count); } // Print deletions From 719969c198a03efca91c8e062b0462af12677557 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:43:18 -0400 Subject: [PATCH 03/16] testing pr comment --- .github/workflows/pr-comment.yml | 77 ++++++++++++++++++++++++++------ src/commands/stats.rs | 20 +++++---- 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index bd5bec82f..35805b605 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -2,37 +2,88 @@ name: PR Comment on Merge on: pull_request: - types: [closed] + types: [opened, synchronize, reopened] + # push: jobs: comment-on-merge: name: Comment on Merged PR runs-on: ubuntu-latest - if: github.event.pull_request.merged == true steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install git-ai + run: | + curl -sSL https://gitai.run/install.sh | bash + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Get git-ai stats + id: git-ai-stats + run: | + export PATH="$HOME/.local/bin:$PATH" + if [ "${{ github.event_name }}" = "push" ]; then + COMMIT_SHA="${{ github.sha }}" + else + COMMIT_SHA="${{ github.event.pull_request.head.sha }}" + fi + git-ai stats $COMMIT_SHA > git_ai_stats.txt + echo "stats_output<> $GITHUB_OUTPUT + cat git_ai_stats.txt >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT + - name: Comment on merged PR uses: actions/github-script@v7 with: script: | const { owner, repo, number } = context.issue; + const commitSha = '${{ steps.git-ai-stats.outputs.commit_sha }}'; + const statsOutput = '${{ steps.git-ai-stats.outputs.stats_output }}'; + const eventName = '${{ github.event_name }}'; + + let title, body; + + if (eventName === 'push') { + title = '🚀 **Code Pushed!**'; + body = `New code has been pushed to the repository. + + **Commit:** \`${commitSha}\` + + **Git-AI Stats for Commit:** + \`\`\` + ${statsOutput} + \`\`\` + + **Next Steps:** + - The changes are now live in the branch + - If this was a feature or bug fix, consider updating the documentation + - If you have any follow-up tasks, please create new issues or PRs - const comment = `🎉 **PR Merged Successfully!** + Thanks for contributing to the project! 🚀`; + } else { + title = '📝 **PR Commit Analysis**'; + body = `Git-AI analysis for this pull request commit. - This pull request has been merged into the main branch. Thank you for your contribution! + **Commit:** \`${commitSha}\` - **Merge Commit:** \`${context.payload.pull_request.merge_commit_sha}\` + **Git-AI Stats for Commit:** + \`\`\` + ${statsOutput} + \`\`\` - **Merge Details:** - - Merged by: @${context.payload.pull_request.merged_by.login} - - Merged at: ${new Date(context.payload.pull_request.merged_at).toLocaleString()} + **Next Steps:** + - Review the AI contribution analysis above + - Consider any suggestions for improvement + - Continue with your development workflow - **Next Steps:** - - The changes are now live in the main branch - - If this was a feature or bug fix, consider updating the documentation - - If you have any follow-up tasks, please create new issues or PRs + Thanks for contributing to the project! 🚀`; + } - Thanks again for contributing to the project! 🚀`; + const comment = `${title}\n\n${body}`; await github.rest.issues.createComment({ owner, diff --git a/src/commands/stats.rs b/src/commands/stats.rs index 560fc9a46..66216cc1f 100644 --- a/src/commands/stats.rs +++ b/src/commands/stats.rs @@ -158,19 +158,23 @@ fn print_stats( } fn print_file_stats(file_path: &str, stats: &FileStats, scale_factor: f64) { - println!("\n{}", file_path); + // Calculate total changes for the file + let total_additions = stats.total_additions; + let total_deletions = stats.deletions; + + // Print file header with total changes + println!( + "\n{} (+{} -{})", + file_path, total_additions, total_deletions + ); // Print additions by author for (author, count) in stats.additions.iter() { - let bar_length = ((*count as f64 * scale_factor).round() as usize).max(1); - let bar = "+".repeat(bar_length); - println!(" {} {} {:>3}", author, bar, count); + println!(" {} (+{})", author, count); } - // Print deletions + // Print deletions (no author attribution) if stats.deletions > 0 { - let bar_length = ((stats.deletions as f64 * scale_factor).round() as usize).max(1); - let bar = "-".repeat(bar_length); - println!(" {} {:>3}", bar, stats.deletions); + println!(" -{}", stats.deletions); } } From 1afda830e87c2d5b0e28ebb5db0289ab0df9a543 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:44:07 -0400 Subject: [PATCH 04/16] cleanup --- src/commands/stats.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/stats.rs b/src/commands/stats.rs index 66216cc1f..288a5bfbf 100644 --- a/src/commands/stats.rs +++ b/src/commands/stats.rs @@ -151,13 +151,13 @@ fn print_stats( // Print totals println!("\nTotal Additions:"); for (author, count) in total_additions_by_author.iter() { - println!(" {} {}", author, count); + println!(" {} +{}", author, count); } - println!("\nTotal Deletions: {}", total_deletions); + println!("\nTotal Deletions: -{}", total_deletions); } -fn print_file_stats(file_path: &str, stats: &FileStats, scale_factor: f64) { +fn print_file_stats(file_path: &str, stats: &FileStats) { // Calculate total changes for the file let total_additions = stats.total_additions; let total_deletions = stats.deletions; From 1296aa41139f1588a5fa7975029b48ce3d1cc331 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:48:10 -0400 Subject: [PATCH 05/16] cleanup --- src/commands/stats.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/commands/stats.rs b/src/commands/stats.rs index 288a5bfbf..09a22a65f 100644 --- a/src/commands/stats.rs +++ b/src/commands/stats.rs @@ -130,22 +130,12 @@ fn print_stats( total_additions_by_author: &HashMap, total_deletions: u32, ) { - // Find the maximum changes for scaling - let max_changes = file_stats - .values() - .map(|stats| stats.total_additions.max(stats.deletions)) - .max() - .unwrap_or(1); - - // Calculate scale factor (minimum 1, maximum 20 characters) - let scale_factor = (20.0 / max_changes as f64).min(1.0); - println!("Statistics for commit:"); println!("{}", "=".repeat(50)); // Print per-file statistics for (file_path, stats) in file_stats.iter() { - print_file_stats(file_path, stats, scale_factor); + print_file_stats(file_path, stats); } // Print totals From bebecf11881ae5d7c98b58da4b0e20bd75c6bbd0 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:54:22 -0400 Subject: [PATCH 06/16] claude fixes gh action --- .github/workflows/pr-comment.yml | 34 +++----------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 35805b605..8040bc731 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -49,41 +49,13 @@ jobs: if (eventName === 'push') { title = '🚀 **Code Pushed!**'; - body = `New code has been pushed to the repository. - - **Commit:** \`${commitSha}\` - - **Git-AI Stats for Commit:** - \`\`\` - ${statsOutput} - \`\`\` - - **Next Steps:** - - The changes are now live in the branch - - If this was a feature or bug fix, consider updating the documentation - - If you have any follow-up tasks, please create new issues or PRs - - Thanks for contributing to the project! 🚀`; + body = statsOutput; } else { title = '📝 **PR Commit Analysis**'; - body = `Git-AI analysis for this pull request commit. - - **Commit:** \`${commitSha}\` - - **Git-AI Stats for Commit:** - \`\`\` - ${statsOutput} - \`\`\` - - **Next Steps:** - - Review the AI contribution analysis above - - Consider any suggestions for improvement - - Continue with your development workflow - - Thanks for contributing to the project! 🚀`; + body = statsOutput; } - const comment = `${title}\n\n${body}`; + const comment = title + '\n\n' + body; await github.rest.issues.createComment({ owner, From c62c97dc3f50446f8909c3cd72800cbeadf09f4d Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:55:59 -0400 Subject: [PATCH 07/16] claude fixes 2 --- .github/workflows/pr-comment.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 8040bc731..98cbe901d 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -31,8 +31,10 @@ jobs: COMMIT_SHA="${{ github.event.pull_request.head.sha }}" fi git-ai stats $COMMIT_SHA > git_ai_stats.txt - echo "stats_output<> $GITHUB_OUTPUT - cat git_ai_stats.txt >> $GITHUB_OUTPUT + # Base64 encode the output to avoid issues with special characters + base64 git_ai_stats.txt > git_ai_stats_base64.txt + echo "stats_output_base64<> $GITHUB_OUTPUT + cat git_ai_stats_base64.txt >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT @@ -42,9 +44,12 @@ jobs: script: | const { owner, repo, number } = context.issue; const commitSha = '${{ steps.git-ai-stats.outputs.commit_sha }}'; - const statsOutput = '${{ steps.git-ai-stats.outputs.stats_output }}'; + const statsOutputBase64 = '${{ steps.git-ai-stats.outputs.stats_output_base64 }}'; const eventName = '${{ github.event_name }}'; + // Decode the base64 stats output + const statsOutput = Buffer.from(statsOutputBase64, 'base64').toString('utf8'); + let title, body; if (eventName === 'push') { From 0f591243e4311cf6f9b03b63b595e8e972016462 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:57:37 -0400 Subject: [PATCH 08/16] claude fixes 3 --- .github/scripts/comment-pr.js | 23 +++++++++++++++++++ .github/workflows/pr-comment.yml | 38 +++++++++----------------------- 2 files changed, 33 insertions(+), 28 deletions(-) create mode 100644 .github/scripts/comment-pr.js diff --git a/.github/scripts/comment-pr.js b/.github/scripts/comment-pr.js new file mode 100644 index 000000000..73b0405b0 --- /dev/null +++ b/.github/scripts/comment-pr.js @@ -0,0 +1,23 @@ +const { owner, repo, number } = context.issue; +const commitSha = process.env.COMMIT_SHA; +const statsOutput = process.env.STATS_OUTPUT; +const eventName = process.env.EVENT_NAME; + +let title, body; + +if (eventName === 'push') { + title = '🚀 **Code Pushed!**'; + body = statsOutput; +} else { + title = '📝 **PR Commit Analysis**'; + body = statsOutput; +} + +const comment = title + '\n\n' + body; + +await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body: comment +}); \ No newline at end of file diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 98cbe901d..3ccfb5528 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -31,10 +31,8 @@ jobs: COMMIT_SHA="${{ github.event.pull_request.head.sha }}" fi git-ai stats $COMMIT_SHA > git_ai_stats.txt - # Base64 encode the output to avoid issues with special characters - base64 git_ai_stats.txt > git_ai_stats_base64.txt - echo "stats_output_base64<> $GITHUB_OUTPUT - cat git_ai_stats_base64.txt >> $GITHUB_OUTPUT + echo "stats_output<> $GITHUB_OUTPUT + cat git_ai_stats.txt >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT @@ -42,29 +40,13 @@ jobs: uses: actions/github-script@v7 with: script: | - const { owner, repo, number } = context.issue; - const commitSha = '${{ steps.git-ai-stats.outputs.commit_sha }}'; - const statsOutputBase64 = '${{ steps.git-ai-stats.outputs.stats_output_base64 }}'; - const eventName = '${{ github.event_name }}'; + const fs = require('fs'); + const script = fs.readFileSync('.github/scripts/comment-pr.js', 'utf8'); - // Decode the base64 stats output - const statsOutput = Buffer.from(statsOutputBase64, 'base64').toString('utf8'); + // Set environment variables for the script + process.env.COMMIT_SHA = '${{ steps.git-ai-stats.outputs.commit_sha }}'; + process.env.STATS_OUTPUT = '${{ steps.git-ai-stats.outputs.stats_output }}'; + process.env.EVENT_NAME = '${{ github.event_name }}'; - let title, body; - - if (eventName === 'push') { - title = '🚀 **Code Pushed!**'; - body = statsOutput; - } else { - title = '📝 **PR Commit Analysis**'; - body = statsOutput; - } - - const comment = title + '\n\n' + body; - - await github.rest.issues.createComment({ - owner, - repo, - issue_number: number, - body: comment - }); + // Execute the script + eval(script); From 1ccb8ab6ed7d072a427130e5ae2dca4405926c56 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 11:58:58 -0400 Subject: [PATCH 09/16] claude fixes 4 --- .github/workflows/pr-comment.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 3ccfb5528..93456ab21 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -5,6 +5,10 @@ on: types: [opened, synchronize, reopened] # push: +permissions: + pull-requests: write + issues: write + jobs: comment-on-merge: name: Comment on Merged PR From 8ef4432f954ff6d9a85bf9f7d0c3233e689ed40b Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 12:00:20 -0400 Subject: [PATCH 10/16] claude fixes 5 --- .github/workflows/pr-comment.yml | 33 ++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 93456ab21..afdfaba46 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -35,22 +35,35 @@ jobs: COMMIT_SHA="${{ github.event.pull_request.head.sha }}" fi git-ai stats $COMMIT_SHA > git_ai_stats.txt - echo "stats_output<> $GITHUB_OUTPUT - cat git_ai_stats.txt >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT - name: Comment on merged PR uses: actions/github-script@v7 with: script: | + const { owner, repo, number } = context.issue; + const commitSha = '${{ steps.git-ai-stats.outputs.commit_sha }}'; + const eventName = '${{ github.event_name }}'; + + // Read stats from file to avoid YAML escaping issues const fs = require('fs'); - const script = fs.readFileSync('.github/scripts/comment-pr.js', 'utf8'); + const statsOutput = fs.readFileSync('git_ai_stats.txt', 'utf8'); + + let title, body; + + if (eventName === 'push') { + title = '🚀 **Code Pushed!**'; + body = statsOutput; + } else { + title = '📝 **PR Commit Analysis**'; + body = statsOutput; + } - // Set environment variables for the script - process.env.COMMIT_SHA = '${{ steps.git-ai-stats.outputs.commit_sha }}'; - process.env.STATS_OUTPUT = '${{ steps.git-ai-stats.outputs.stats_output }}'; - process.env.EVENT_NAME = '${{ github.event_name }}'; + const comment = title + '\n\n' + body; - // Execute the script - eval(script); + await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body: comment + }); From f56111c0f0236b74faee93e5481c13fd321c6f92 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 12:01:38 -0400 Subject: [PATCH 11/16] claude fixes 6 --- .github/workflows/pr-comment.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index afdfaba46..79d1cf823 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -53,10 +53,10 @@ jobs: if (eventName === 'push') { title = '🚀 **Code Pushed!**'; - body = statsOutput; + body = '```\n' + statsOutput + '\n```'; } else { title = '📝 **PR Commit Analysis**'; - body = statsOutput; + body = '```\n' + statsOutput + '\n```'; } const comment = title + '\n\n' + body; From f1f0f679242fd953a5770638a80fa5126702f1ce Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 12:03:54 -0400 Subject: [PATCH 12/16] fix history --- .github/workflows/pr-comment.yml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 79d1cf823..6c2432f00 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -3,7 +3,7 @@ name: PR Comment on Merge on: pull_request: types: [opened, synchronize, reopened] - # push: + push: permissions: pull-requests: write @@ -41,7 +41,6 @@ jobs: uses: actions/github-script@v7 with: script: | - const { owner, repo, number } = context.issue; const commitSha = '${{ steps.git-ai-stats.outputs.commit_sha }}'; const eventName = '${{ github.event_name }}'; @@ -54,16 +53,24 @@ jobs: if (eventName === 'push') { title = '🚀 **Code Pushed!**'; body = '```\n' + statsOutput + '\n```'; + + // For push events, create a commit comment + await github.rest.repos.createCommitComment({ + owner: context.repo.owner, + repo: context.repo.repo, + commit_sha: commitSha, + body: title + '\n\n' + body + }); } else { title = '📝 **PR Commit Analysis**'; body = '```\n' + statsOutput + '\n```'; + + // For PR events, create a PR comment + const { owner, repo, number } = context.issue; + await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body: title + '\n\n' + body + }); } - - const comment = title + '\n\n' + body; - - await github.rest.issues.createComment({ - owner, - repo, - issue_number: number, - body: comment - }); From 54163023a0e73f2f17cb9f54b367c2b7c759653a Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 12:05:26 -0400 Subject: [PATCH 13/16] claude 6 --- .github/workflows/pr-comment.yml | 42 ++++++++------------------------ 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 6c2432f00..5df9e5cfb 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -3,7 +3,6 @@ name: PR Comment on Merge on: pull_request: types: [opened, synchronize, reopened] - push: permissions: pull-requests: write @@ -29,11 +28,7 @@ jobs: id: git-ai-stats run: | export PATH="$HOME/.local/bin:$PATH" - if [ "${{ github.event_name }}" = "push" ]; then - COMMIT_SHA="${{ github.sha }}" - else - COMMIT_SHA="${{ github.event.pull_request.head.sha }}" - fi + COMMIT_SHA="${{ github.event.pull_request.head.sha }}" git-ai stats $COMMIT_SHA > git_ai_stats.txt echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT @@ -41,36 +36,19 @@ jobs: uses: actions/github-script@v7 with: script: | + const { owner, repo, number } = context.issue; const commitSha = '${{ steps.git-ai-stats.outputs.commit_sha }}'; - const eventName = '${{ github.event_name }}'; // Read stats from file to avoid YAML escaping issues const fs = require('fs'); const statsOutput = fs.readFileSync('git_ai_stats.txt', 'utf8'); - let title, body; + const title = '📝 **PR Commit Analysis**'; + const body = '```\n' + statsOutput + '\n```'; - if (eventName === 'push') { - title = '🚀 **Code Pushed!**'; - body = '```\n' + statsOutput + '\n```'; - - // For push events, create a commit comment - await github.rest.repos.createCommitComment({ - owner: context.repo.owner, - repo: context.repo.repo, - commit_sha: commitSha, - body: title + '\n\n' + body - }); - } else { - title = '📝 **PR Commit Analysis**'; - body = '```\n' + statsOutput + '\n```'; - - // For PR events, create a PR comment - const { owner, repo, number } = context.issue; - await github.rest.issues.createComment({ - owner, - repo, - issue_number: number, - body: title + '\n\n' + body - }); - } + await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body: title + '\n\n' + body + }); From 4925f14532c7f01805089f8742a775efc32a6cae Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 12:07:50 -0400 Subject: [PATCH 14/16] aidan fixes refs issue --- .github/workflows/pr-comment.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 5df9e5cfb..ceb58bc3d 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -19,6 +19,11 @@ jobs: with: fetch-depth: 0 + - name: Fetch AI refs + run: | + git fetch origin refs/ai/*:refs/ai/* + git fetch origin refs/ai/*:refs/remotes/origin/ai/* + - name: Install git-ai run: | curl -sSL https://gitai.run/install.sh | bash From 03c09275096ace7da9fe84f15e2ad8d58b2d59cc Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 12:08:51 -0400 Subject: [PATCH 15/16] claude change --- .github/workflows/pr-comment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index ceb58bc3d..0a97d494e 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -19,6 +19,7 @@ jobs: with: fetch-depth: 0 + # Grab the refs since actions shallow clones by default - name: Fetch AI refs run: | git fetch origin refs/ai/*:refs/ai/* From 1222aabc84ea6b4d2a830f7ddb4ac3b9c01c8da0 Mon Sep 17 00:00:00 2001 From: Aidan Cunniffe Date: Sat, 5 Jul 2025 12:10:15 -0400 Subject: [PATCH 16/16] demo --- .github/scripts/comment-pr.js | 5 ++--- src/commands/stats.rs | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/scripts/comment-pr.js b/.github/scripts/comment-pr.js index 73b0405b0..e15750d86 100644 --- a/.github/scripts/comment-pr.js +++ b/.github/scripts/comment-pr.js @@ -3,13 +3,12 @@ const commitSha = process.env.COMMIT_SHA; const statsOutput = process.env.STATS_OUTPUT; const eventName = process.env.EVENT_NAME; -let title, body; +let body; +let title = 'Live demo of git-ai:'; if (eventName === 'push') { - title = '🚀 **Code Pushed!**'; body = statsOutput; } else { - title = '📝 **PR Commit Analysis**'; body = statsOutput; } diff --git a/src/commands/stats.rs b/src/commands/stats.rs index 09a22a65f..6fa5b4f2e 100644 --- a/src/commands/stats.rs +++ b/src/commands/stats.rs @@ -130,7 +130,6 @@ fn print_stats( total_additions_by_author: &HashMap, total_deletions: u32, ) { - println!("Statistics for commit:"); println!("{}", "=".repeat(50)); // Print per-file statistics