Skip to content

refactor(sdk/go): unify functional-option handling with shared applier - #3232

Open
rhuss wants to merge 2 commits into
NVIDIA:mainfrom
rhuss:6118-unify-go-sdk-options
Open

refactor(sdk/go): unify functional-option handling with shared applier#3232
rhuss wants to merge 2 commits into
NVIDIA:mainfrom
rhuss:6118-unify-go-sdk-options

Conversation

@rhuss

@rhuss rhuss commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Summary

The Go SDK applied functional options with hand-copied for _, o := range opts { o(&cfg) } loops at 15 sites across six areas. None guarded against a nil option, so a nil entry in an option list panicked everywhere. This unifies option application behind a single generic helper and adopts one rule: nil options are ignored.

Related Issue

Closes #3213

Changes

  • Add openshell/v1/internal/options (new leaf package) with
    Apply[T any, O ~func(*T)](target *T, opts []O) — skips nil entries, applies the rest in order.
  • Route all 15 application sites (root package, types, oidc, fake, gateway, edge)
    through options.Apply. Exported types.Apply*Options helpers keep their signatures and delegate.
  • Preserve each site's existing pre-seeding and post-applyDefaults() ordering; only nil handling changes.
  • Add one nil-handling test per affected package plus unit tests for the helper.
  • Document the nil-option rule in sdk/go/README.md and the docs book (docs/src/architecture.md).

No public API signature changes; consumers compile unchanged.

Testing

  • mise run go:ci green: build, golangci-lint, gofmt, full go test, proto-check, docs-check.
  • New per-package nil tests exercise a list mixing nil and non-nil options (nil ignored, both valid options applied).

Checklist

Signed-off-by: Roland Huß <rhuss@redhat.com>
Introduce a single generic applier, options.Apply[T any, O ~func(*T)],
in a new leaf package openshell/v1/internal/options, and route all
option-application sites through it. Nil option entries are now ignored
uniformly instead of panicking; non-nil options still apply in order,
and each site keeps its existing pre-seeding and defaulting.

- Add internal/options package with Apply and unit tests
- Route the 15 application sites (root, types, oidc, fake, gateway, edge)
  through options.Apply; exported types.Apply*Options keep their
  signatures and delegate to it
- Add one nil-handling test per affected package
- Document the nil-option rule in README.md and the docs book

No public API signature changes.

Closes NVIDIA#3213

Signed-off-by: Roland Huß <rhuss@redhat.com>
@copy-pr-bot

copy-pr-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

Comment thread sdk/go/openshell/v1/internal/options/options.go
Comment thread sdk/go/openshell/v1/fake/fake.go
Comment on lines 86 to 99
fc.sandboxes = sandboxes
fc.templateCreate = sandboxes
fc.templates = newFakeSandboxTemplateClient(fc.templateStore, fc.isClosed)
fc.providers = newFakeProviderClient(fc.providerStore, fc.isClosed)
fc.services = newFakeServiceClient(fc.isClosed)
fc.exec = newFakeExecClient(fc.isClosed)
fc.files = newFakeFileClient(fc.isClosed)
fc.health = newFakeHealthClient(nil, fc.isClosed)
fc.ssh = newFakeSSHClient(fc.isClosed)
fc.tcp = newFakeTCPClient(fc.isClosed)
fc.cfg = newFakeConfigClient(fc.isClosed)
fc.policy = newFakePolicyClient(fc.isClosed)
fc.workspaces = newFakeWorkspaceClient(fc.workspaceStore, fc.memberStore, fc.isClosed)
fc.inference = newFakeInferenceClient(fc.isClosed)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of scope: Instead of applying these directly, should we also model them as ClientOptions?

Comment on lines +41 to 42
options.Apply(cfg, opts)
cfg.applyDefaults()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also out of scope: Why do we apply defaults after applying the inputs? Does this mean that user inputs could be overridden?

Comment thread .gitignore
Comment on lines +239 to +247

# spex: generated/local files (only constitution is committed)
**/.claude/
**/.agents/
**/.codex/
**/.specify/**
!**/.specify/spex.json
!**/.specify/memory/
!**/.specify/memory/constitution.md

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change related to this PR? Note that the .agents folder in this repo is explicitly used for contributor workflows.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, this slipped in from my SDD flow (but I'm getting there, already was able to reliably exclude the main SDD artefacts). Going to remove this change.

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.

refactor(sdk/go): unify nil handling and apply-loop pattern for functional options

2 participants