Skip to content

CLI-981 Import telemetry: emit UserOnboardingStarted / Completed / Exited - #698

Closed
bjorn-vonubisch-sonarsource wants to merge 4 commits into
masterfrom
bjorn-vonubisch-sonarsource/import-telemetry-onboarding-started
Closed

bjorn-vonubisch-sonarsource wants to merge 4 commits into
masterfrom
bjorn-vonubisch-sonarsource/import-telemetry-onboarding-started

Conversation

@bjorn-vonubisch-sonarsource

Copy link
Copy Markdown
Contributor

Summary

Adds three Gessie telemetry events to sonar import that mirror the sonarcloud-webapp's onboarding event schema, with source: 'cli' instead of 'ui'.


Events

Analytics.Cli.UserOnboardingStarted

Fired at the very start of importHandler, immediately after the intro banner, before any org or repo resolution happens.

Field Type Value
devops_platform string | null Always null at start (ALM not yet resolved)
plan string | null Always null (not available in CLI context)
source 'cli' Fixed
user_uuid string | null Resolved from telemetry identity
version string Running CLI version (e.g. 1.2.3)

Analytics.Cli.UserOnboardingCompleted

Fired after the import job finishes (whether all repos succeeded or some failed), before reportOutcome renders the result. Fires for both the streaming (--all / --regex) and batch (--repo) flows.

Field Type Value
devops_platform string | null ALM key resolved from the org (e.g. github, azure), or null if unavailable
import_method 'bulk' | 'single' 'bulk' for streaming (--all / --regex), 'single' for batch (--repo)
organization_uuid_v4 string | null Resolved from telemetry identity
plan string | null Always null (not available in CLI context)
project_count number Number of repositories successfully imported
source 'cli' Fixed
user_uuid string | null Resolved from telemetry identity
version string Running CLI version

Analytics.Cli.UserOnboardingExited

Fired when the flow is aborted before UserOnboardingCompleted — i.e. any error that prevents the import from finishing (org not found, unsupported ALM, page-fetch failure mid-stream, etc.). Not fired when reportOutcome throws due to partial repo failures, because UserOnboardingCompleted has already been emitted by then.

Field Type Value
destination string 'error' (type of cancellation)
devops_platform string | null ALM key if it was resolved before the error, otherwise null
plan string | null Always null
source 'cli' Fixed
user_uuid string | null Resolved from telemetry identity
version string Running CLI version

Implementation notes

  • Payloads deliberately do not extend TelemetryEventIdentityPayload — they carry only user_uuid / organization_uuid_v4 drawn from the identity base, matching the lean webapp schema.
  • event_version: '0' is set in metadata on all three events (matching webapp convention).
  • All three emit calls are fire-and-forget (.catch(() => {})), so a telemetry failure never affects the import result.
  • A completedEmitted flag gates UserOnboardingExited: set to true after each emitUserOnboardingCompleted call, checked in the catch block to avoid double-firing.

Test plan

  • Run sonar import against a real org and verify the three events land in telemetry-events.ndjson
  • Trigger an error early (e.g. an org without a connected DevOps platform) and verify UserOnboardingExited fires with devops_platform: null
  • Trigger an error after ALM resolution and verify UserOnboardingExited fires with the correct devops_platform
  • Let an import complete with failures and verify only UserOnboardingCompleted fires (not UserOnboardingExited)

🤖 Generated with Claude Code

…d events

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@netlify

netlify Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for sonarqube-cli canceled.

Name Link
🔨 Latest commit a223341
🔍 Latest deploy log https://app.netlify.com/projects/sonarqube-cli/deploys/6a85be50a1a5df0008b0d3da

@hashicorp-vault-sonar-prod hashicorp-vault-sonar-prod Bot changed the title CLI-XXX Import telemetry: emit UserOnboardingStarted / Completed / Exited CLI-981 CLI-XXX Import telemetry: emit UserOnboardingStarted / Completed / Exited Aug 19, 2026
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

CLI-981

@bjorn-vonubisch-sonarsource bjorn-vonubisch-sonarsource changed the title CLI-981 CLI-XXX Import telemetry: emit UserOnboardingStarted / Completed / Exited CLI-981 Import telemetry: emit UserOnboardingStarted / Completed / Exited Aug 19, 2026
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread src/commands/import/index.ts Outdated
Comment thread src/core/telemetry/telemetry-events.ts Outdated
Comment thread src/commands/import/index.ts
- Inline resolveOrgAndRepos into importHandler so almKey is assigned
  before assertSupportedAlm; UserOnboardingExited now carries the real
  devops_platform even when the ALM is unsupported
- Add unit tests for emitUserOnboardingStarted/Completed/Exited covering
  envelope shape, lean payload (no CLI identity fields), and telemetry-
  disabled no-ops

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread src/commands/import/index.ts
@gitar-bot

gitar-bot Bot commented Aug 19, 2026 •

Copy link
Copy Markdown
Code Review ✅ Approved 4 closed / 4 findings

Adds import telemetry events for onboarding started, completed, and exited states with unit test coverage. Consider refining how null onboarding fields and unauthenticated ALM keys are handled during serialization.

✅ 4 closed
✅ Edge Case: Exited event reports null ALM for unsupported-ALM errors

📄 src/commands/import/index.ts:243-247 📄 src/commands/import/index.ts:304-312 📄 src/commands/import/index.ts:79-81
In importHandler, almKey is only assigned (line 247) after resolveOrgAndRepos returns. But resolveOrgAndRepos resolves the real ALM key internally and then throws in assertSupportedAlm (index.ts:81) for unsupported platforms — before returning. So any error raised inside resolveOrgAndRepos (org lookup, unsupported ALM, repo resolution) reaches the catch block with almKey still undefined, emitting UserOnboardingExited with devops_platform: null even though the platform was known. This contradicts the PR's stated goal of capturing the ALM on exit for post-resolution errors. Consider having resolveOrgAndRepos surface the resolved almKey before assertSupportedAlm (e.g. attach it to the thrown error, or resolve org/ALM in importHandler before the try boundary) so the exited event carries the correct platform.

✅ Quality: New telemetry emit functions have no unit tests

📄 src/core/telemetry/telemetry-events.ts:184-198 📄 src/commands/import/index.ts:241-255
emitUserOnboardingStarted/Completed/Exited are added with no unit tests, while every sibling emitter (emitAnalysisCompleted, emitIntegrationConfigured, emitCommandExecuted) is covered in tests/unit/core/telemetry/telemetry-events.test.ts. The completed-vs-exited gating via completedEmitted in importHandler (the trickiest new logic) is also untested. Add cases asserting the event envelopes (event_type, event_version '0', lean payload shape) and that UserOnboardingExited fires only when UserOnboardingCompleted has not, per the project's testing conventions.

Closed: Edge Case: Always-null onboarding fields are stripped before transmit

📄 src/core/telemetry/telemetry-events.ts:345 📄 src/commands/import/index.ts:241
flushTelemetryEvents serializes each event with a replacer that converts every null to undefined (telemetry-events.ts:345), so null-valued keys are dropped from the transmitted JSON. For UserOnboardingStarted both meaningful fields (devops_platform, plan) are always null and will never be sent, and other events lose these keys whenever null. If the Gessie/webapp schema expects the fields to be present (even as null), the backend may receive incomplete events. Verify the backend tolerates absent keys, or the lean design of these events may not land as intended.

Closed: Edge Case: Exited event reports null ALM if entitlement check rejects

📄 src/commands/import/index.ts:209 📄 src/commands/import/index.ts:219-223 📄 src/commands/import/index.ts:290-294
The comment claims UserOnboardingExited "always carries the platform," but almKey is only assigned (line 223) after the Promise.all at line 219 resolves. If client.hasPrivateProjectsEntitlement rejects while resolveAlmKey would have succeeded, almKey stays undefined and the exited event reports devops_platform: null despite the ALM being resolvable. To honor the comment, assign almKey from resolveAlmKey's result independently of the entitlement call (e.g. resolve the ALM first, or capture it in a .then before the combined await).

Review coverage

Functional validation No results

Rules No rules evaluated

Auto-approval Not enabled · Set up

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

…ctions

Extract `appendLeanOnboardingEvent` private helper shared by
`emitUserOnboardingStarted` and `emitUserOnboardingExited`, which had
identical bodies differing only in event type. Also fix Prettier
formatting on import/index.ts to pass the lint check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant