|
1 | 1 | import * as vscode from "vscode" |
2 | 2 | import * as path from "path" |
3 | 3 | import { promises as fs } from "fs" |
| 4 | +import { exec } from "child_process" |
| 5 | +import { promisify } from "util" |
| 6 | + |
| 7 | +const execAsync = promisify(exec) |
4 | 8 |
|
5 | 9 | export interface GitRepositoryInfo { |
6 | 10 | repositoryUrl?: string |
@@ -156,32 +160,126 @@ export async function getWorkspaceGitInfo(): Promise<GitRepositoryInfo> { |
156 | 160 | } |
157 | 161 |
|
158 | 162 | /** |
159 | | - * Gets git commit information - stub implementation |
160 | | - * @param workspaceRoot The workspace root directory |
161 | | - * @returns Promise resolving to commit info |
| 163 | + * Gets git commit information for a specific commit hash |
| 164 | + * @param commitHash The commit hash to get information for |
| 165 | + * @param workspaceRoot Optional workspace root directory (if not provided, uses the first workspace folder) |
| 166 | + * @returns Promise resolving to formatted commit info string |
162 | 167 | */ |
163 | | -export async function getCommitInfo(workspaceRoot: string): Promise<GitCommit[]> { |
164 | | - // TODO: Implement git commit retrieval |
165 | | - return [] |
| 168 | +export async function getCommitInfo(commitHash: string, workspaceRoot?: string): Promise<string> { |
| 169 | + try { |
| 170 | + // Get workspace root if not provided |
| 171 | + if (!workspaceRoot) { |
| 172 | + const workspaceFolders = vscode.workspace.workspaceFolders |
| 173 | + if (!workspaceFolders || workspaceFolders.length === 0) { |
| 174 | + return "" |
| 175 | + } |
| 176 | + workspaceRoot = workspaceFolders[0].uri.fsPath |
| 177 | + } |
| 178 | + |
| 179 | + // Check if .git directory exists |
| 180 | + const gitDir = path.join(workspaceRoot, ".git") |
| 181 | + try { |
| 182 | + await fs.access(gitDir) |
| 183 | + } catch { |
| 184 | + // Not a git repository |
| 185 | + return "" |
| 186 | + } |
| 187 | + |
| 188 | + // Use git show to get detailed commit information |
| 189 | + // The format is similar to what git show would normally output |
| 190 | + const command = `git -C "${workspaceRoot}" show --no-patch --format="%H %s%n%nAuthor: %an%nDate: %ad" ${commitHash}` |
| 191 | + |
| 192 | + const { stdout } = await execAsync(command) |
| 193 | + return stdout.trim() |
| 194 | + } catch (error) { |
| 195 | + console.error(`Error retrieving git commit info: ${error instanceof Error ? error.message : String(error)}`) |
| 196 | + return "" |
| 197 | + } |
166 | 198 | } |
167 | 199 |
|
168 | 200 | /** |
169 | | - * Gets git working state - stub implementation |
| 201 | + * Gets git working state - checks if there are uncommitted changes |
170 | 202 | * @param workspaceRoot The workspace root directory |
171 | 203 | * @returns Promise resolving to working state info |
172 | 204 | */ |
173 | 205 | export async function getWorkingState(workspaceRoot: string): Promise<{ hasChanges: boolean }> { |
174 | | - // TODO: Implement git working state check |
175 | | - return { hasChanges: false } |
| 206 | + try { |
| 207 | + // Check if .git directory exists |
| 208 | + const gitDir = path.join(workspaceRoot, ".git") |
| 209 | + try { |
| 210 | + await fs.access(gitDir) |
| 211 | + } catch { |
| 212 | + // Not a git repository |
| 213 | + return { hasChanges: false } |
| 214 | + } |
| 215 | + |
| 216 | + // Use git status --porcelain for machine-readable output |
| 217 | + // If there are changes, it will output lines describing the changes |
| 218 | + // If there are no changes, the output will be empty |
| 219 | + const command = `git -C "${workspaceRoot}" status --porcelain` |
| 220 | + |
| 221 | + const { stdout } = await execAsync(command) |
| 222 | + |
| 223 | + // If stdout is not empty, there are changes |
| 224 | + return { hasChanges: stdout.trim() !== "" } |
| 225 | + } catch (error) { |
| 226 | + console.error(`Error checking git working state: ${error instanceof Error ? error.message : String(error)}`) |
| 227 | + return { hasChanges: false } |
| 228 | + } |
176 | 229 | } |
177 | 230 |
|
178 | 231 | /** |
179 | | - * Searches git commits - stub implementation |
180 | | - * @param workspaceRoot The workspace root directory |
181 | | - * @param query The search query |
| 232 | + * Searches git commits matching a query string |
| 233 | + * @param query The search query (searches commit messages) |
| 234 | + * @param workspaceRoot Optional workspace root directory (if not provided, uses the first workspace folder) |
| 235 | + * @param limit Maximum number of commits to retrieve (default: 20) |
182 | 236 | * @returns Promise resolving to matching commits |
183 | 237 | */ |
184 | | -export async function searchCommits(workspaceRoot: string, query: string): Promise<GitCommit[]> { |
185 | | - // TODO: Implement git commit search |
186 | | - return [] |
| 238 | +export async function searchCommits(query: string, workspaceRoot?: string, limit: number = 20): Promise<GitCommit[]> { |
| 239 | + try { |
| 240 | + // Get workspace root if not provided |
| 241 | + if (!workspaceRoot) { |
| 242 | + const workspaceFolders = vscode.workspace.workspaceFolders |
| 243 | + if (!workspaceFolders || workspaceFolders.length === 0) { |
| 244 | + return [] |
| 245 | + } |
| 246 | + workspaceRoot = workspaceFolders[0].uri.fsPath |
| 247 | + } |
| 248 | + |
| 249 | + // Check if .git directory exists |
| 250 | + const gitDir = path.join(workspaceRoot, ".git") |
| 251 | + try { |
| 252 | + await fs.access(gitDir) |
| 253 | + } catch { |
| 254 | + // Not a git repository |
| 255 | + return [] |
| 256 | + } |
| 257 | + |
| 258 | + // Format: hash, author, date, message |
| 259 | + // %H: full hash, %an: author name, %ad: author date, %s: subject (message) |
| 260 | + const format = "--pretty=format:%H|%an|%ad|%s" |
| 261 | + |
| 262 | + // Use git log with grep to search commit messages |
| 263 | + // The -i flag makes the search case-insensitive |
| 264 | + const command = `git -C "${workspaceRoot}" log ${format} -n ${limit} --grep="${query}" -i` |
| 265 | + |
| 266 | + const { stdout } = await execAsync(command) |
| 267 | + |
| 268 | + // Parse the output into GitCommit objects |
| 269 | + return stdout |
| 270 | + .split("\n") |
| 271 | + .filter((line) => line.trim() !== "") |
| 272 | + .map((line) => { |
| 273 | + const [hash, author, date, message] = line.split("|") |
| 274 | + return { |
| 275 | + hash, |
| 276 | + author, |
| 277 | + date, |
| 278 | + message, |
| 279 | + } |
| 280 | + }) |
| 281 | + } catch (error) { |
| 282 | + console.error(`Error searching git commits: ${error instanceof Error ? error.message : String(error)}`) |
| 283 | + return [] |
| 284 | + } |
187 | 285 | } |
0 commit comments