feat(v2/events/snowplow): add WithContext option to TrackEvent

What does this MR do and why?

Adds a WithContext functional option to Tracker.TrackEvent so callers can attach one or more Snowplow context entities (SelfDescribingJSON) alongside an event payload — for example, the gitlab_standard context, or any service-specific context.

Closes #103 (closed).

Note on CI: I haven't enabled instance runners on my fork (blocked on free-account identity verification, which I'd rather not pursue just for this MR). Labkit has ci_allow_fork_pipelines_to_run_in_parent_project: true, so a maintainer can run the pipeline in the parent project context with one click. Local verification on this branch is already green: cd v2 && go test -race ./events/snowplow/... passes, golangci-lint run ./events/snowplow/... reports 0 issues.

Why this design

  • Functional options match existing labkit idioms (WithCallback, WithTokenSource, WithMetricsCollectorOptions) — no new public types other than the option function.
  • Backward compatible: existing TrackEvent(name, props) calls compile and behave identically. No context is encoded when none is supplied. Satisfies the v2 stability principle ("never add required parameters").
  • Encoding mirrors billing events: contexts are wrapped in a SchemaContexts envelope and base64-encoded into payload.ContextEncoded, the same path that TrackBillingEventWithOptionalInput already uses for the billable_usage context.
  • Multiple contexts accumulate; nil entries are filtered.

Usage

gitlabStandard := &snowplow.SelfDescribingJSON{
    Schema: "iglu:com.gitlab/gitlab_standard/jsonschema/1-1-8",
    Data: map[string]any{
        "environment": "production",
        "source":      "artifact-registry",
    },
}

err := tracker.TrackEvent(
    "artifact_downloaded",
    map[string]any{"size_bytes": 1048576},
    snowplow.WithContext(gitlabStandard),
)

Changes

  • New file v2/events/snowplow/tracker_options.go — defines TrackEventOption and the WithContext option.
  • tracker.go — adds opts ...TrackEventOption to TrackEvent; encodes contexts when present, otherwise leaves ContextEncoded empty.
  • tracker_test.go — adds TestTrackEvent_Context, a table-driven test with five subtests covering: no options, nil-only context filtered, single context, multiple contexts via one variadic call, and multiple WithContext calls accumulating.
  • examples_test.go — adds ExampleTracker_TrackEvent_withContext demonstrating attaching a gitlab_standard context.

Public API surface added: WithContext and TrackEventOption. Both are documented.

How to test

cd v2 && go test -race ./events/snowplow/...

All existing tests still pass. New tests verify both the encoded-payload shape (the SchemaContexts envelope, contained schemas in declared order) and the no-context path (ContextEncoded stays empty).

golangci-lint run ./events/snowplow/... reports 0 issues.

Notes for reviewers

  • I deliberately avoided changing TrackBillingEvent* — it already attaches a context via a different (non-optional) path. Unifying the two would be scope creep for this issue; happy to do a follow-up MR if preferred.
  • Variadic opts ...TrackEventOption is preferred over a sibling TrackEventWithContext method because (a) it composes with future options without further API churn and (b) it mirrors NewEmitter(url, opts...) already in this package.
Edited by manas srivastava

Merge request reports

Loading