Skip to content

Commit c4b97c4

Browse files
committed
added git to telemetry, git utils, fix typing error
1 parent 07b3593 commit c4b97c4

File tree

3 files changed

+121
-25
lines changed

3 files changed

+121
-25
lines changed

packages/types/src/telemetry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ export const gitPropertiesSchema = z.object({
8181
export const telemetryPropertiesSchema = z.object({
8282
...appPropertiesSchema.shape,
8383
...taskPropertiesSchema.shape,
84+
...gitPropertiesSchema.shape,
8485
})
8586

8687
export const cloudTelemetryPropertiesSchema = z.object({
8788
...telemetryPropertiesSchema.shape,
88-
...gitPropertiesSchema.shape,
8989
})
9090

9191
export type TelemetryProperties = z.infer<typeof telemetryPropertiesSchema>

src/core/webview/ClineProvider.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,9 @@ export class ClineProvider
17151715

17161716
const packageJSON = this.context.extension?.packageJSON
17171717

1718+
// Get git repository information
1719+
const gitInfo = await getWorkspaceGitInfo()
1720+
17181721
return {
17191722
appName: packageJSON?.name ?? Package.name,
17201723
appVersion: packageJSON?.version ?? Package.version,
@@ -1727,6 +1730,7 @@ export class ClineProvider
17271730
modelId: task?.api?.getModel().id,
17281731
diffStrategy: task?.diffStrategy?.getName(),
17291732
isSubtask: task ? !!task.parentTask : undefined,
1733+
...gitInfo, // Include Git information in all telemetry events
17301734
}
17311735
}
17321736

@@ -1735,14 +1739,8 @@ export class ClineProvider
17351739
* This method is called by cloud telemetry clients to get extended context
17361740
*/
17371741
public async getCloudTelemetryProperties(): Promise<CloudTelemetryProperties> {
1738-
const baseTelemetryProperties = await this.getTelemetryProperties()
1739-
1740-
// Get git repository information
1741-
const gitInfo = await getWorkspaceGitInfo()
1742-
1743-
return {
1744-
...baseTelemetryProperties,
1745-
...gitInfo,
1746-
}
1742+
// Since getTelemetryProperties now includes Git information with defaults,
1743+
// we can simply return its result as CloudTelemetryProperties
1744+
return (await this.getTelemetryProperties()) as CloudTelemetryProperties
17471745
}
17481746
}

src/utils/git.ts

Lines changed: 113 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import * as vscode from "vscode"
22
import * as path from "path"
33
import { promises as fs } from "fs"
4+
import { exec } from "child_process"
5+
import { promisify } from "util"
6+
7+
const execAsync = promisify(exec)
48

59
export interface GitRepositoryInfo {
610
repositoryUrl?: string
@@ -156,32 +160,126 @@ export async function getWorkspaceGitInfo(): Promise<GitRepositoryInfo> {
156160
}
157161

158162
/**
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
162167
*/
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+
}
166198
}
167199

168200
/**
169-
* Gets git working state - stub implementation
201+
* Gets git working state - checks if there are uncommitted changes
170202
* @param workspaceRoot The workspace root directory
171203
* @returns Promise resolving to working state info
172204
*/
173205
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+
}
176229
}
177230

178231
/**
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)
182236
* @returns Promise resolving to matching commits
183237
*/
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+
}
187285
}

0 commit comments

Comments
 (0)