-
Notifications
You must be signed in to change notification settings - Fork 1
Implement parallel git diff analysis algorithm to improve performance #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 21 commits
5f39241
5c4b7b3
1f7edd0
ed71a85
b262f78
997ac3d
8257f3d
c78fe5a
c099808
eeb34bb
9623080
cd7f92c
6994218
dbbff52
036b1da
7221b16
c4396e3
f946e61
c63b1f0
fa8f571
457eff0
a1337e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,12 +3,10 @@ | |
| **/*.log | ||
| *.log | ||
| http-cacache/ | ||
| .git | ||
| .gitignore | ||
| .dockerignore | ||
| Dockerfile | ||
| **/Dockerfile | ||
| **/.git | ||
| **/.gitignore | ||
| **/.dockerignore | ||
|
Comment on lines
6
to
11
|
||
| .editorconfig | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -22,22 +22,15 @@ jobs: | |||||||||||||||||||||
| cache-on-failure: true | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Setup nightly toolchain | ||||||||||||||||||||||
| uses: actions-rs/toolchain@v1 | ||||||||||||||||||||||
| uses: dtolnay/rust-toolchain@nightly | ||||||||||||||||||||||
| with: | ||||||||||||||||||||||
| components: rustfmt, clippy | ||||||||||||||||||||||
| toolchain: nightly | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Run clippy | ||||||||||||||||||||||
| uses: actions-rs/cargo@v1 | ||||||||||||||||||||||
| with: | ||||||||||||||||||||||
| command: clippy | ||||||||||||||||||||||
| args: -- -D warnings | ||||||||||||||||||||||
| run: cargo clippy -- -D warnings | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Run cargo fmt | ||||||||||||||||||||||
| uses: actions-rs/cargo@v1 | ||||||||||||||||||||||
| with: | ||||||||||||||||||||||
| command: fmt | ||||||||||||||||||||||
| args: -- --check | ||||||||||||||||||||||
| run: cargo fmt -- --check | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| test: | ||||||||||||||||||||||
| needs: lint | ||||||||||||||||||||||
|
|
@@ -54,25 +47,29 @@ jobs: | |||||||||||||||||||||
| with: | ||||||||||||||||||||||
| cache-on-failure: true | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Set up Rust | ||||||||||||||||||||||
| uses: actions-rs/toolchain@v1 | ||||||||||||||||||||||
| with: | ||||||||||||||||||||||
| toolchain: ${{ matrix.rust }} | ||||||||||||||||||||||
| override: true | ||||||||||||||||||||||
| profile: minimal | ||||||||||||||||||||||
| - name: Set up Rust (nightly) | ||||||||||||||||||||||
| if: matrix.rust == 'nightly' | ||||||||||||||||||||||
| uses: dtolnay/rust-toolchain@nightly | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Set up Rust (stable) | ||||||||||||||||||||||
| if: matrix.rust == 'stable' | ||||||||||||||||||||||
| uses: dtolnay/rust-toolchain@stable | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Install fish (Linux) | ||||||||||||||||||||||
| if: startsWith(matrix.os, 'ubuntu') | ||||||||||||||||||||||
| run: sudo apt install fish | ||||||||||||||||||||||
| run: sudo apt update && sudo apt install -y fish | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Install fish (macOS) | ||||||||||||||||||||||
| if: startsWith(matrix.os, 'macos') | ||||||||||||||||||||||
| run: brew install fish | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Run integration tests | ||||||||||||||||||||||
| if: env.OPENAI_API_KEY != '' | ||||||||||||||||||||||
| run: fish ./scripts/integration-tests | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| - name: Skip integration tests (no API key) | ||||||||||||||||||||||
| if: env.OPENAI_API_KEY == '' | ||||||||||||||||||||||
|
Comment on lines
+67
to
+71
|
||||||||||||||||||||||
| if: env.OPENAI_API_KEY != '' | |
| run: fish ./scripts/integration-tests | |
| - name: Skip integration tests (no API key) | |
| if: env.OPENAI_API_KEY == '' | |
| if: ${{ env.OPENAI_API_KEY != '' }} | |
| run: fish ./scripts/integration-tests | |
| - name: Skip integration tests (no API key) | |
| if: ${{ env.OPENAI_API_KEY == '' }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| use anyhow::Result; | ||
| use ai::multi_step_integration::{generate_commit_message_parallel, parse_diff}; | ||
| use async_openai::Client; | ||
|
|
||
| /// Demonstrates the new parallel commit message generation approach | ||
| /// This example shows how the parallel algorithm processes multiple files concurrently | ||
| #[tokio::main] | ||
| async fn main() -> Result<()> { | ||
| // Initialize logging to see the parallel processing in action | ||
| env_logger::init(); | ||
|
|
||
| println!("Parallel Commit Message Generation Demo"); | ||
| println!("======================================"); | ||
| println!(); | ||
|
|
||
| // Example multi-file diff to demonstrate parallel processing | ||
| let multi_file_diff = r#"diff --git a/src/auth.rs b/src/auth.rs | ||
| index 1234567..abcdefg 100644 | ||
| --- a/src/auth.rs | ||
| +++ b/src/auth.rs | ||
| @@ -1,8 +1,15 @@ | ||
| +use crate::security::hash; | ||
| +use crate::database::UserStore; | ||
| + | ||
| pub struct AuthService { | ||
| users: HashMap<String, User>, | ||
| } | ||
|
|
||
| impl AuthService { | ||
| + pub fn new(store: UserStore) -> Self { | ||
| + Self { users: store.load_users() } | ||
| + } | ||
| + | ||
| pub fn authenticate(&self, username: &str, password: &str) -> Result<Token> { | ||
| - // Simple hardcoded check | ||
| - if username == "admin" && password == "secret" { | ||
| + // Enhanced security with proper hashing | ||
| + let hashed = hash(password); | ||
| + if self.users.get(username).map(|u| &u.password_hash) == Some(&hashed) { | ||
| Ok(Token::new(username)) | ||
| } else { | ||
| Err(AuthError::InvalidCredentials) | ||
| diff --git a/src/main.rs b/src/main.rs | ||
| index abcd123..efgh456 100644 | ||
| --- a/src/main.rs | ||
| +++ b/src/main.rs | ||
| @@ -1,8 +1,12 @@ | ||
| +mod auth; | ||
| +mod security; | ||
| +mod database; | ||
| + | ||
| use std::collections::HashMap; | ||
|
|
||
| fn main() { | ||
| println!("Starting application"); | ||
|
|
||
| - // TODO: Add authentication | ||
| + let auth = auth::AuthService::new(database::UserStore::new()); | ||
| + println!("Authentication service initialized"); | ||
| } | ||
| diff --git a/Cargo.toml b/Cargo.toml | ||
| index 9876543..1111111 100644 | ||
| --- a/Cargo.toml | ||
| +++ b/Cargo.toml | ||
| @@ -6,4 +6,6 @@ edition = "2021" | ||
| [dependencies] | ||
| serde = "1.0" | ||
| tokio = "1.0" | ||
| +bcrypt = "0.14" | ||
| +sqlx = "0.7" | ||
| "#; | ||
|
|
||
| println!("1. Parsing diff to identify files for parallel processing..."); | ||
| let parsed_files = parse_diff(multi_file_diff)?; | ||
| println!(" Found {} files to analyze:", parsed_files.len()); | ||
| for (i, file) in parsed_files.iter().enumerate() { | ||
| println!(" {}. {} ({})", i + 1, file.path, file.operation); | ||
| } | ||
| println!(); | ||
|
|
||
| println!("2. Demonstrating the parallel analysis approach:"); | ||
| println!(" - Each file will be analyzed concurrently (not sequentially)"); | ||
| println!(" - Uses simple text completion (not complex function calling)"); | ||
| println!(" - Single synthesis step replaces 3 sequential API calls"); | ||
| println!(); | ||
|
|
||
| // Note: This would require a valid OpenAI API key to actually run | ||
| // For the demo, we just show the structure | ||
| if std::env::var("OPENAI_API_KEY").is_ok() { | ||
| println!("3. Running parallel analysis (requires OpenAI API key)..."); | ||
|
|
||
| let client = Client::new(); | ||
| let model = "gpt-4o-mini"; | ||
|
|
||
| match generate_commit_message_parallel(&client, model, multi_file_diff, Some(72)).await { | ||
| Ok(message) => { | ||
| println!(" ✓ Generated commit message: '{}'", message); | ||
| println!(" ✓ Message length: {} characters", message.len()); | ||
| } | ||
| Err(e) => { | ||
| println!(" ⚠ API call failed (expected without valid key): {}", e); | ||
| } | ||
| } | ||
| } else { | ||
| println!("3. Skipping API call (no OPENAI_API_KEY found)"); | ||
| println!(" Set OPENAI_API_KEY environment variable to test with real API"); | ||
| } | ||
|
|
||
| println!(); | ||
| println!("Performance Benefits:"); | ||
| println!("• Single file: ~6.6s → ~4s (eliminate 2 sequential round-trips)"); | ||
| println!("• Multiple files: Linear scaling vs sequential (5 files: ~4.3s vs ~16s)"); | ||
| println!("• Better error resilience: Continue if some files fail to analyze"); | ||
| println!(); | ||
|
|
||
| println!("Architecture Improvements:"); | ||
| println!("• Two-phase design: Parallel analysis → Unified synthesis"); | ||
| println!("• Simplified API: Plain text responses vs function calling schemas"); | ||
| println!("• Graceful fallback: Falls back to original multi-step if parallel fails"); | ||
|
|
||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
.gitignorepattern appears to be duplicated - line 6 has.gitignoreand line 10 has**/.gitignore. The more specific pattern**/.gitignoreshould cover the general case, making the first entry redundant.