Skip to content

refactor(kosli): add a typed Kosli API client core - #1248

Draft
dangrondahl wants to merge 11 commits into
mainfrom
refactor/kosli-client
Draft

dangrondahl wants to merge 11 commits into
mainfrom
refactor/kosli-client

Conversation

@dangrondahl

@dangrondahl dangrondahl commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Commands build every Kosli API call themselves. Each one joins global.Host with api/v2 and global.Org, passes global.ApiToken, and guards against the (nil, nil) that requests.Client.Do returns on a dry run. Most of them then decode the body by hand. There are 80 such call sites, and some endpoints are built in two or three places.

This PR adds internal/kosli, a client that will hold one file per tag of the OpenAPI spec. It follows the conventions of terraform-provider-kosli/pkg/client: ctx first, typed structs next to each endpoint, and Is* error helpers. This first slice is only the core. It has no endpoints and no callers yet, and nothing in cmd/kosli changes.

  • New(sender, host, org, token). Endpoint files will build on two unexported helpers, endpoint(segments…) and send(ctx, params).
  • Result{Raw, Created} and Response[T], which embeds Result. Raw is the server's body exactly as it arrived, so --output json can keep printing it unchanged. Response[T] decodes the body only when Value() is called. That way --output json never decodes, and a field the type doesn't fit fails only the output that reads it (review of refactor(get artifact, assert artifact): fetch through the Kosli API client #1269). Created replaces the res.Resp.StatusCode == 200 checks.
  • DryRun(sender) is a sender adapter. GETs still reach the server, as they do today. Writes are logged and not sent, using the existing payload printing in requests. A dry-run result is an empty Result, not nil.
  • APIError is an alias of requests.APIError, with IsNotFound, IsConflict and IsForbidden added.

Changes to internal/requests

  • RequestParams.Context is new. Nil means context.Background(), so existing callers are unaffected.
  • Transport errors are now wrapped with %w instead of %v. The message is the same, and errors.Is(err, context.Canceled) now works.

Worth knowing

A 409, 5xx or 429 is retried. When the retries run out, the caller gets a plain "giving up after N attempt(s)" error and not an APIError. IsConflict therefore only matches a request that sets DisableConflictRetry. This is the same as on main.

Next slices

Each slice is its own PR, stacked on this one:

  1. GetTrail, used by get trail and evaluate. This slice also builds the client in PersistentPreRunE.
  2. Artifacts
  3. Environments, with snapshotReporter moved into the client
  4. Evaluations
  5. Attestations
  6. The remaining tags, one per PR

Tests

There are 12 httptest tests in internal/kosli. make lint is clean. I have not run the integration suite locally for this PR.

Checklist

@github-actions github-actions Bot added go Pull requests that update go code refactor labels Oct 5, 2026
@claude

claude Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @dangrondahl's task in 1m 11s —— View job


Follow-up review: commits 21c70882..44547df0

  • Fetch prior review findings
  • Diff BEFORE..AFTER commits
  • Assess resolution status of each prior finding
  • Check changed lines for new bugs/regressions
  • Post inline comments for new issues (none needed)
  • Post summary comment

The new commits in this range touch only internal/kosli/client.go and internal/kosli/client_test.go, changing decode[T]/Response[T].Value into a lazy (*Response[T]).Value() method (commit 44547df0). None of the three prior findings' locations are touched by this range — their fixes (131a7472, c624320e) landed in earlier commits, before the BEFORE sha:

  1. client_test.go:35 (race-unsafe require.NoError in the server goroutine) — resolved, thread closed.
  2. dryrun.go (method allow-list + mutating caller's params) — resolved, thread closed.
  3. client.go:75 (dry-run Created ambiguity) — acknowledged by the author as intentional (kept out of Result by design); no code change, thread closed.

Reviewed the lazy-decode change itself (not previously flagged) for regressions: it's correct — Value() still returns the zero value on an empty body, still wraps unmarshal errors the same way, and Raw stays untouched on a decode error so --output json is unaffected. No new bugs found; no inline comments posted.

Branch: refactor/kosli-client

Comment thread internal/kosli/client_test.go
Comment thread internal/kosli/dryrun.go Outdated
Comment thread internal/kosli/client.go
@dangrondahl
dangrondahl force-pushed the refactor/kosli-client branch from c624320 to 21c7088 Compare October 15, 2026 14:22
@dangrondahl
dangrondahl added this pull request to stack #1272 October 15, 2026 15:11

This branch has not been deployed

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

Labels

go Pull requests that update go code refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant