From 33e90ef8ad30d04939b4bbfe4397fd2f83817364 Mon Sep 17 00:00:00 2001 From: erguotou Date: Fri, 3 Jan 2025 18:06:43 +0800 Subject: [PATCH] ci: enhance test setup and improve auto commit message generation; configure git user details and refine hook script --- packages/core/__test__/index.spec.mjs | 6 +- packages/core/src/auto_commit.rs | 196 +++++++++++++------------- packages/core/src/hooks.rs | 16 +-- 3 files changed, 104 insertions(+), 114 deletions(-) diff --git a/packages/core/__test__/index.spec.mjs b/packages/core/__test__/index.spec.mjs index f12ccec..7ddb0a2 100644 --- a/packages/core/__test__/index.spec.mjs +++ b/packages/core/__test__/index.spec.mjs @@ -9,9 +9,11 @@ import { init, install, runHook } from '../index.js' const testDir = path.join(fileURLToPath(import.meta.url), '../..') test.beforeEach('mkdir test dir', async (t) => { + execSync('git config --global user.email "test@example.com"') + execSync('git config --global user.name "Test User"') execSync('git init') - // await fs.mkdir(testDir, { recursive: true }) - // process.chdir(testDir) + await new Promise(resolve => setTimeout(resolve, 100)) + console.log('Finish git init') }) test.afterEach('rm test dir', async (t) => { // process.chdir(startDir) diff --git a/packages/core/src/auto_commit.rs b/packages/core/src/auto_commit.rs index adb26f5..e4ac9f1 100644 --- a/packages/core/src/auto_commit.rs +++ b/packages/core/src/auto_commit.rs @@ -2,31 +2,31 @@ use crate::command::run_command; use crate::config; use reqwest::Client; use serde_json::json; +use spinners::{Spinner, Spinners}; use std::env; use std::process::{Command, Stdio}; -use spinners::{Spinner, Spinners}; pub async fn generate_commit_message(commit: bool) -> Result<(), String> { - let config = config::check()?; - if !config.ai.enabled { - return Err("Auto commit is not enabled".to_string()); - } - // 获取git diff内容 - let diff = get_git_diff()?; - if diff.is_empty() { - return Err("No changes to commit".to_string()); - } + let config = config::check()?; + if !config.ai.enabled { + return Err("Auto commit is not enabled".to_string()); + } + // 获取git diff内容 + let diff = get_git_diff()?; + if diff.is_empty() { + return Err("No changes to commit".to_string()); + } - let api_key = config - .ai - .api_key - .or_else(|| env::var("OPENAI_API_KEY").ok()) - .ok_or("API key not found")?; - let base_url = config.ai.base_url.unwrap(); - let model = config.ai.model.unwrap(); + let api_key = config + .ai + .api_key + .or_else(|| env::var("OPENAI_API_KEY").ok()) + .ok_or("API key not found")?; + let base_url = config.ai.base_url.unwrap(); + let model = config.ai.model.unwrap(); - // Build prompt - let system_prompt = "You are a git commit message generator. Generate a concise, standardized commit message directly with no format wrapper based on the git diff. Focus on the overall purpose or functionality of the changes, rather than listing individual file changes. Follow these guidelines:\n\ + // Build prompt + let system_prompt = "You are a git commit message generator. Generate a concise, standardized commit message directly with no format wrapper based on the git diff. Focus on the overall purpose or functionality of the changes, rather than listing individual file changes. Follow these guidelines:\n\ - **Type**: Choose one of the following: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.\n\ - **Scope**: Optional scope of the commit, like 'cli', 'core', 'ui', 'api', etc.\n\ - **Description**: A short one-line description starting with a present-tense verb, summarizing the overall change.\n\ @@ -45,94 +45,94 @@ pub async fn generate_commit_message(commit: bool) -> Result<(), String> { - Focus on the high-level purpose of the commit.\n\ - Keep the description concise and meaningful.\n\ - Only include a body or footer if they add significant value."; - let system_prompt = if let Some(lang) = config.ai.respond_in { - format!( - "{}\nPlease always generate the commit message in {} language", - system_prompt, lang - ) - } else { - system_prompt.to_string() - }; + let system_prompt = if let Some(lang) = config.ai.respond_in { + format!( + "{}\nPlease always generate the commit message in {} language", + system_prompt, lang + ) + } else { + system_prompt.to_string() + }; - let messages = vec![ - json!({ - "role": "system", - "content": system_prompt - }), - json!({ - "role": "user", - "content": diff - }), - ]; + let messages = vec![ + json!({ + "role": "system", + "content": system_prompt + }), + json!({ + "role": "user", + "content": diff + }), + ]; - let client = Client::new(); - let mut spinner = Spinner::new(Spinners::Dots, "Generating commit message...".into()); - let response = client - .post(format!("{}/chat/completions", base_url)) - .header("Content-Type", "application/json") - .header("Authorization", format!("Bearer {}", api_key)) - .json(&json!({ - "model": model, - "messages": messages, - "temperature": 0.0 - })) - .send() - .await - .map_err(|e| format!("Failed to send request: {}", e))?; + let client = Client::new(); + let mut spinner = Spinner::new(Spinners::Dots, "Generating commit message...".into()); + let response = client + .post(format!("{}/chat/completions", base_url)) + .header("Content-Type", "application/json") + .header("Authorization", format!("Bearer {}", api_key)) + .json(&json!({ + "model": model, + "messages": messages, + "temperature": 0.0 + })) + .send() + .await + .map_err(|e| format!("Failed to send request: {}", e))?; - let response_json: serde_json::Value = response - .json() - .await - .map_err(|e| format!("Failed to parse response: {}", e))?; + let response_json: serde_json::Value = response + .json() + .await + .map_err(|e| format!("Failed to parse response: {}", e))?; - spinner.stop(); + spinner.stop(); - let content = response_json["choices"][0]["message"]["content"] - .as_str() - .ok_or("Invalid response format") - .map_err(|e| format!("Failed to parse response: {}", e))? - .to_string(); + let content = response_json["choices"][0]["message"]["content"] + .as_str() + .ok_or("Invalid response format") + .map_err(|e| format!("Failed to parse response: {}", e))? + .to_string(); - println!("{}", content); - if content.is_empty() { - return Err("No commit message generated".to_string()); - } - if commit { - run_command("git", &format!("commit -m \"{}\"", content)) - .map_err(|e| format!("Failed to commit: {}", e))?; - } else { - let mut ps_commit = Command::new("git") - .arg("commit") - .arg("-e") - .arg("-m") - .arg(content) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .spawn() - .unwrap(); - ps_commit.wait().unwrap(); - } - Ok(()) + println!("{}", content); + if content.is_empty() { + return Err("No commit message generated".to_string()); + } + if commit { + run_command("git", &format!("commit -m \"{}\"", content)) + .map_err(|e| format!("Failed to commit: {}", e))?; + } else { + let mut ps_commit = Command::new("git") + .arg("commit") + .arg("-e") + .arg("-m") + .arg(content) + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn() + .unwrap(); + ps_commit.wait().unwrap(); + } + Ok(()) } fn get_git_diff() -> Result { - let output = Command::new("git") - .args(&[ - "diff", - "--staged", - "--ignore-all-space", - "--diff-algorithm=minimal", - "--function-context", - "--no-ext-diff", - "--no-color", - ]) - .output() - .map_err(|e| format!("Failed to get git diff: {}", e))?; + let output = Command::new("git") + .args(&[ + "diff", + "--staged", + "--ignore-all-space", + "--diff-algorithm=minimal", + "--function-context", + "--no-ext-diff", + "--no-color", + ]) + .output() + .map_err(|e| format!("Failed to get git diff: {}", e))?; - if !output.status.success() { - return Err("Git diff command failed".to_string()); - } + if !output.status.success() { + return Err("Git diff command failed".to_string()); + } - Ok(String::from_utf8_lossy(&output.stdout).to_string()) + Ok(String::from_utf8_lossy(&output.stdout).to_string()) } diff --git a/packages/core/src/hooks.rs b/packages/core/src/hooks.rs index 77cea2b..3acb94d 100644 --- a/packages/core/src/hooks.rs +++ b/packages/core/src/hooks.rs @@ -57,22 +57,10 @@ pub fn install() -> Result<(), Box> { // generate hooks for hook_name in hooks.iter() { let hook_path = hooks_dir.join(hook_name); - let bin_entry_path = Path::new("./node_modules/@doremijs/igit-cli/bin/index.mjs"); let hook_content = format!( - r#"#!/bin/sh -run_command() {{ - if command -v bun > /dev/null 2>&1; then - bun "$@" - elif command -v deno > /dev/null 2>&1; then - deno run "$@" - else - node "$@" - fi -}} - -run_command {} run "{}" "$@" + r#"#!/usr/bin/env sh +npx igit run "{}" "$@" "#, - bin_entry_path.to_string_lossy(), hook_name ); fs::write(&hook_path, hook_content)?;