feat(telemetry): track if session is running in a Git worktree (#23265)

This commit is contained in:
Jerop Kipruto
2026-03-20 15:01:12 -04:00
committed by GitHub
parent 62cb14fa52
commit b459e1a108
6 changed files with 80 additions and 41 deletions
@@ -687,6 +687,11 @@ export class ClearcutLogger {
gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_EXTENSION_IDS,
value: event.extension_ids.toString(),
},
{
gemini_cli_key:
EventMetadataKey.GEMINI_CLI_START_SESSION_WORKTREE_ACTIVE,
value: event.worktree_active.toString(),
},
];
// Add hardware information only to the start session event
@@ -452,6 +452,9 @@ export enum EventMetadataKey {
// Logs the name of extensions as a comma-separated string
GEMINI_CLI_START_SESSION_EXTENSION_IDS = 120,
// Logs whether the session is running in a Git worktree.
GEMINI_CLI_START_SESSION_WORKTREE_ACTIVE = 191,
// Logs the setting scope for an extension enablement.
GEMINI_CLI_EXTENSION_ENABLE_SETTING_SCOPE = 102,
+67 -41
View File
@@ -195,48 +195,51 @@ describe('loggers', () => {
});
describe('logCliConfiguration', () => {
const baseMockConfig = {
getSessionId: () => 'test-session-id',
getModel: () => 'test-model',
getEmbeddingModel: () => 'test-embedding-model',
getSandbox: () => true,
getCoreTools: () => ['ls', 'read-file'],
getApprovalMode: () => 'default',
getContentGeneratorConfig: () => ({
model: 'test-model',
apiKey: 'test-api-key',
authType: AuthType.USE_VERTEX_AI,
}),
getTelemetryEnabled: () => true,
getUsageStatisticsEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
getFileFilteringRespectGitIgnore: () => true,
getFileFilteringAllowBuildArtifacts: () => false,
getDebugMode: () => true,
getMcpServers: () => {
throw new Error('Should not call');
},
getQuestion: () => 'test-question',
getTargetDir: () => 'target-dir',
getProxy: () => 'http://test.proxy.com:8080',
getOutputFormat: () => OutputFormat.JSON,
getExtensions: () =>
[
{ name: 'ext-one', id: 'id-one' },
{ name: 'ext-two', id: 'id-two' },
] as GeminiCLIExtension[],
getMcpClientManager: () => ({
getMcpServers: () => ({
'test-server': {
command: 'test-command',
},
}),
}),
isInteractive: () => false,
getExperiments: () => undefined,
getExperimentsAsync: async () => undefined,
getWorktreeSettings: () => undefined,
} as unknown as Config;
it('should log the cli configuration', async () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getModel: () => 'test-model',
getEmbeddingModel: () => 'test-embedding-model',
getSandbox: () => true,
getCoreTools: () => ['ls', 'read-file'],
getApprovalMode: () => 'default',
getContentGeneratorConfig: () => ({
model: 'test-model',
apiKey: 'test-api-key',
authType: AuthType.USE_VERTEX_AI,
}),
getTelemetryEnabled: () => true,
getUsageStatisticsEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
getFileFilteringRespectGitIgnore: () => true,
getFileFilteringAllowBuildArtifacts: () => false,
getDebugMode: () => true,
getMcpServers: () => {
throw new Error('Should not call');
},
getQuestion: () => 'test-question',
getTargetDir: () => 'target-dir',
getProxy: () => 'http://test.proxy.com:8080',
getOutputFormat: () => OutputFormat.JSON,
getExtensions: () =>
[
{ name: 'ext-one', id: 'id-one' },
{ name: 'ext-two', id: 'id-two' },
] as GeminiCLIExtension[],
getMcpClientManager: () => ({
getMcpServers: () => ({
'test-server': {
command: 'test-command',
},
}),
}),
isInteractive: () => false,
getExperiments: () => undefined,
getExperimentsAsync: async () => undefined,
} as unknown as Config;
const mockConfig = baseMockConfig;
const startSessionEvent = new StartSessionEvent(mockConfig);
logCliConfiguration(mockConfig, startSessionEvent);
@@ -270,9 +273,32 @@ describe('loggers', () => {
extensions_count: 2,
extensions: 'ext-one,ext-two',
auth_type: 'vertex-ai',
worktree_active: false,
},
});
});
it('should set worktree_active to true when worktree settings are present', async () => {
const mockConfig = {
...baseMockConfig,
getWorktreeSettings: () => ({
name: 'test-worktree',
path: '/path/to/worktree',
baseSha: 'test-sha',
}),
} as unknown as Config;
const startSessionEvent = new StartSessionEvent(mockConfig);
logCliConfiguration(mockConfig, startSessionEvent);
await new Promise(process.nextTick);
expect(mockLogger.emit).toHaveBeenCalledWith({
body: 'CLI configuration loaded.',
attributes: expect.objectContaining({
worktree_active: true,
}),
});
});
});
describe('logUserPrompt', () => {
+3
View File
@@ -77,6 +77,7 @@ export class StartSessionEvent implements BaseTelemetryEvent {
extensions: string;
extension_ids: string;
auth_type?: string;
worktree_active: boolean;
constructor(config: Config, toolRegistry?: ToolRegistry) {
const generatorConfig = config.getContentGeneratorConfig();
@@ -114,6 +115,7 @@ export class StartSessionEvent implements BaseTelemetryEvent {
this.extensions = extensions.map((e) => e.name).join(',');
this.extension_ids = extensions.map((e) => e.id).join(',');
this.auth_type = generatorConfig?.authType;
this.worktree_active = !!config.getWorktreeSettings();
if (toolRegistry) {
const mcpTools = toolRegistry
.getAllTools()
@@ -147,6 +149,7 @@ export class StartSessionEvent implements BaseTelemetryEvent {
extensions_count: this.extensions_count,
extension_ids: this.extension_ids,
auth_type: this.auth_type,
worktree_active: this.worktree_active,
};
}