Skip to content

Commit ec9e6c2

Browse files
committed
fix: init telemetry in gateway PersistentPreRunE and add regression tests
- Call initTelemetry(cmd) in gateway's PersistentPreRunE so gateway subcommands send non-empty CLI telemetry (command_path, device_name, etc.). Cobra does not chain PersistentPreRun; adding requireGatewayProject in #237 replaced root's hook and skipped initTelemetry. - Add TestInitTelemetryWhenDisabled: initTelemetry must run even when telemetry is disabled (singleton is still populated; header is skipped in PerformRequest). - Add TestAllCommandsWithPersistentPreRunInitTelemetry: any command with its own PersistentPreRun(E) must call initTelemetry(cmd) so the test fails if a new command overrides the hook without initializing telemetry. Made-with: Cursor
1 parent cd28a92 commit ec9e6c2

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

pkg/cmd/gateway.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ The gateway command group provides full access to all Event Gateway resources.`,
7070
# Start the MCP server for AI agent access
7171
hookdeck gateway mcp`,
7272
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
73+
initTelemetry(cmd)
7374
return requireGatewayProject(nil)
7475
},
7576
}

pkg/cmd/telemetry_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,60 @@ func TestInitTelemetryResetBetweenCalls(t *testing.T) {
8585
require.Equal(t, "device-2", tel2.DeviceName)
8686
require.NotEqual(t, id1, tel2.InvocationID)
8787
}
88+
89+
// TestInitTelemetryWhenDisabled verifies that initTelemetry always populates the
90+
// singleton (Source, CommandPath, etc.) even when telemetry is disabled. The
91+
// call must happen for every command; PerformRequest later skips sending the
92+
// header when Disabled is true.
93+
func TestInitTelemetryWhenDisabled(t *testing.T) {
94+
hookdeck.ResetTelemetryInstanceForTesting()
95+
96+
Config.TelemetryDisabled = true
97+
defer func() { Config.TelemetryDisabled = false }()
98+
99+
cmd := &cobra.Command{Use: "whoami"}
100+
Config.DeviceName = "my-device"
101+
initTelemetry(cmd)
102+
103+
tel := hookdeck.GetTelemetryInstance()
104+
require.True(t, tel.Disabled)
105+
require.Equal(t, "cli", tel.Source)
106+
require.Equal(t, "whoami", tel.CommandPath)
107+
require.Equal(t, "my-device", tel.DeviceName)
108+
require.NotEmpty(t, tel.InvocationID)
109+
}
110+
111+
// TestAllCommandsWithPersistentPreRunInitTelemetry is a regression test: any
112+
// command that defines its own PersistentPreRun or PersistentPreRunE (and thus
113+
// replaces the root's hook under Cobra) must call initTelemetry(cmd) so that
114+
// API requests get non-empty telemetry. Otherwise the header is sent with empty
115+
// fields (e.g. gateway before the fix).
116+
func TestAllCommandsWithPersistentPreRunInitTelemetry(t *testing.T) {
117+
root := RootCmd()
118+
var commandsWithPreRun []*cobra.Command
119+
var walk func(c *cobra.Command)
120+
walk = func(c *cobra.Command) {
121+
if c.PersistentPreRun != nil || c.PersistentPreRunE != nil {
122+
commandsWithPreRun = append(commandsWithPreRun, c)
123+
}
124+
for _, child := range c.Commands() {
125+
walk(child)
126+
}
127+
}
128+
walk(root)
129+
130+
require.NotEmpty(t, commandsWithPreRun, "expected at least root to have PersistentPreRun")
131+
132+
for _, cmd := range commandsWithPreRun {
133+
hookdeck.ResetTelemetryInstanceForTesting()
134+
if cmd.PersistentPreRunE != nil {
135+
_ = cmd.PersistentPreRunE(cmd, nil)
136+
} else {
137+
cmd.PersistentPreRun(cmd, nil)
138+
}
139+
tel := hookdeck.GetTelemetryInstance()
140+
require.NotEmpty(t, tel.CommandPath,
141+
"command %q has PersistentPreRun(E) but did not set telemetry (CommandPath empty); it must call initTelemetry(cmd)",
142+
cmd.CommandPath())
143+
}
144+
}

0 commit comments

Comments
 (0)