Skip to content

fix: unstructured type handling#1960

Merged
matthiasbruns merged 3 commits into
open-component-model:mainfrom
matthiasbruns:fix/unstructured_type_handling
Mar 13, 2026
Merged

fix: unstructured type handling#1960
matthiasbruns merged 3 commits into
open-component-model:mainfrom
matthiasbruns:fix/unstructured_type_handling

Conversation

@matthiasbruns

@matthiasbruns matthiasbruns commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it

Unstructured could not parse type from strings like "ociArtifact/v2" and was therefore not fully supported in Scheme.Convert. This was found during work on #1943

For the time being I chose only to add support for Unstructured -> Typed conversion in registry.go and added a string fallback in GetType() in unstructured.go.

Which issue(s) this PR fixes

Contributes: open-component-model/ocm-project#918

Testing

Verification

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced type parsing to handle string-based type values with improved fallback behavior, increasing robustness when retrieving type information.

@matthiasbruns matthiasbruns requested a review from a team as a code owner March 12, 2026 13:00
@coderabbitai

coderabbitai Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The changes enhance the GetType() method in the Unstructured type to parse string-based type values when the direct type attribute is unavailable, with comprehensive test coverage validating the new fallback behavior across multiple scenarios.

Changes

Cohort / File(s) Summary
GetType Enhancement
bindings/go/runtime/unstructured.go
Enhanced GetType() with fallback logic to parse string-formatted type values using TypeFromString when the direct IdentityAttributeType fails to yield a Type. Added inline TODO comment in generic Get[T any] method.
Test Coverage
bindings/go/runtime/unstructured_test.go
Added TestUnstructured_GetType table-driven test validating GetType() across scenarios: versioned/unversioned types, string parsing, invalid/missing fields, and JSON-unmarshaled data extraction.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A parser's delight, we must confess,
When types hide as strings—oh what a mess!
But fallback logic makes parsing divine,
With tests that validate, everything's fine!
Hopping forward with confidence, line by line!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: unstructured type handling' directly summarizes the main change: adding string parsing fallback to GetType() to fix type handling in the Unstructured type.
Linked Issues check ✅ Passed The PR addresses the core coding requirement from #918: enabling type parsing from strings like 'ociArtifact/v2' in GetType() to support Scheme.Convert and toOCI() functionality. A comprehensive test was added validating the new behavior.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing type handling in unstructured.go and its tests. No unrelated modifications detected beyond the intended GetType() string fallback implementation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bindings/go/runtime/unstructured_test.go (1)

78-83: ⚠️ Potential issue | 🟡 Minor

Pre-existing test assertions don't match the test data.

This existing test case has incorrect assertions:

  • The JSON contains "type": "OCIRegistry" but the assertion checks for "OCIRepository"
  • The assertion checks runtime.Get[string](un, "componentNameMapping") equals "OCIRepository", but the actual value in the JSON is "urlPath"

This appears to be a pre-existing bug in the test file, but it will cause test failures.

🐛 Proposed fix for the test assertions
 		assertUnstructured: func(t *testing.T, un *runtime.Unstructured) {
-			assert.Equal(t, "OCIRepository", un.GetType())
+			assert.Equal(t, runtime.NewUnversionedType("OCIRegistry"), un.GetType())
 			value, ok := runtime.Get[string](un, "componentNameMapping")
 			require.True(t, ok)
-			assert.Equal(t, "OCIRepository", value)
+			assert.Equal(t, "urlPath", value)
 		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/unstructured_test.go` around lines 78 - 83, The test
assertions in the assertUnstructured closure are incorrect for the provided
JSON: update the expected type from "OCIRepository" to "OCIRegistry" and update
the expected value fetched via runtime.Get[string](un, "componentNameMapping")
from "OCIRepository" to "urlPath" so the assertions match the test data; locate
the assertUnstructured function/closure in unstructured_test.go and change the
two assert.Equal calls accordingly.
🧹 Nitpick comments (2)
bindings/go/runtime/registry_convert_test.go (1)

267-279: Good documentation of unsupported conversion.

This test correctly documents that Typed → Unstructured conversion is not supported. Consider adding a code comment or updating the Convert method's documentation to explicitly mention this limitation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/registry_convert_test.go` around lines 267 - 279, Add
explicit documentation and an inline code comment to clarify that converting a
typed object to runtime.Unstructured via scheme.Convert is unsupported; update
the Convert method's docstring (the Convert function on the scheme type) to
state this limitation and reference the TestConvert_TypedToUnstructured test as
an example, and add a short comment above the test or the scheme.MustRegister
call explaining that Typed → Unstructured conversion fails by design due to
reflection assignment limitations.
bindings/go/runtime/unstructured.go (1)

46-63: Stale TODO comment should be removed or clarified.

The TODO on line 47 says "check if string, parse type otherwise use below" but the code already implements this logic. Either remove the TODO or clarify what remains to be done.

Also, there's a subtle edge case: when Get[Type] succeeds but returns a zero-value Type (e.g., if someone explicitly stored runtime.Type{} in the map), the function returns that zero value without attempting string parsing. This seems intentional but worth noting.

🧹 Remove stale TODO
 func (u *Unstructured) GetType() Type {
-	// TODO check if string, parse type otherwise use below
 	v, ok := Get[Type](u, IdentityAttributeType)
 	if !ok {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/unstructured.go` around lines 46 - 63, Remove the stale
TODO in Unstructured.GetType and replace it with a short clarifying comment that
documents the intended behavior: that the function first attempts to
Get[Type](u, IdentityAttributeType) and will return that value (including a
zero-value Type if present), and only if that lookup fails will it attempt to
Get[string], parse via TypeFromString and fall back to NewUnversionedType;
explicitly note the zero-value edge case so future readers know this is
intentional.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindings/go/runtime/registry.go`:
- Around line 425-441: The convertFromUnstructured function in Scheme doesn't
handle converting into a *Raw target: after marshaling from.Data it always
json.Unmarshal into into, but Raw has a json:"-" field (Raw.Data) so it never
gets populated; update Scheme.convertFromUnstructured to detect if into is a
*Raw (type assertion to *Raw), and if so set raw.Data = canonicalized marshaled
bytes (use the same marshaled data variable, canonicalize if project expects
canonical JSON) and return nil; keep the existing IsRegistered/allowUnknown
checks and existing error handling for non-Raw targets, and only bypass
json.Unmarshal when into is *Raw.

---

Outside diff comments:
In `@bindings/go/runtime/unstructured_test.go`:
- Around line 78-83: The test assertions in the assertUnstructured closure are
incorrect for the provided JSON: update the expected type from "OCIRepository"
to "OCIRegistry" and update the expected value fetched via
runtime.Get[string](un, "componentNameMapping") from "OCIRepository" to
"urlPath" so the assertions match the test data; locate the assertUnstructured
function/closure in unstructured_test.go and change the two assert.Equal calls
accordingly.

---

Nitpick comments:
In `@bindings/go/runtime/registry_convert_test.go`:
- Around line 267-279: Add explicit documentation and an inline code comment to
clarify that converting a typed object to runtime.Unstructured via
scheme.Convert is unsupported; update the Convert method's docstring (the
Convert function on the scheme type) to state this limitation and reference the
TestConvert_TypedToUnstructured test as an example, and add a short comment
above the test or the scheme.MustRegister call explaining that Typed →
Unstructured conversion fails by design due to reflection assignment
limitations.

In `@bindings/go/runtime/unstructured.go`:
- Around line 46-63: Remove the stale TODO in Unstructured.GetType and replace
it with a short clarifying comment that documents the intended behavior: that
the function first attempts to Get[Type](u, IdentityAttributeType) and will
return that value (including a zero-value Type if present), and only if that
lookup fails will it attempt to Get[string], parse via TypeFromString and fall
back to NewUnversionedType; explicitly note the zero-value edge case so future
readers know this is intentional.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e3d76469-6d39-4840-b5da-5b50a31d846c

📥 Commits

Reviewing files that changed from the base of the PR and between 1844459 and 3041eaf.

📒 Files selected for processing (4)
  • bindings/go/runtime/registry.go
  • bindings/go/runtime/registry_convert_test.go
  • bindings/go/runtime/unstructured.go
  • bindings/go/runtime/unstructured_test.go

Comment thread bindings/go/runtime/registry.go Outdated
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
@matthiasbruns matthiasbruns force-pushed the fix/unstructured_type_handling branch from 3041eaf to 6309a5d Compare March 12, 2026 13:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
bindings/go/runtime/registry_convert_test.go (1)

229-236: Assert raw.Type in the Unstructured → Raw test.

The JSON round-trip proves the payload still contains the type string, but it will not catch a regression where Raw.UnmarshalJSON stops populating raw.Type—the field Scheme.Convert uses on the next hop.

✅ Small test hardening
 	raw := &runtime.Raw{}
 	err := scheme.Convert(un, raw)
 	require.NoError(t, err)
+	assert.Equal(t, typ, raw.Type)

 	var parsed TestType
 	require.NoError(t, json.Unmarshal(raw.Data, &parsed))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/registry_convert_test.go` around lines 229 - 236, Add an
assertion that raw.Type is populated after converting the Unstructured to
runtime.Raw: after calling scheme.Convert(un, raw) (and require.NoError), assert
that raw.Type equals the expected typ (the same variable used later) to catch
regressions in Raw.UnmarshalJSON; reference runtime.Raw, scheme.Convert and
Raw.UnmarshalJSON and place the check before unmarshalling raw.Data into
TestType.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindings/go/runtime/registry.go`:
- Around line 433-439: The Convert path currently unmarshals JSON into the
existing destination, preserving prior fields/keys; before calling
json.Unmarshal for the "into" variable in registry.go (the Convert function),
reset the destination to its zero value so the decode behaves like a full
replacement. Implement this by using reflect on the incoming pointer
(reflect.ValueOf(into).Elem()) and either set it to reflect.Zero of its type
(for structs and slices) or make an empty map/slice as appropriate so
json.Unmarshal writes into a clean value; do this reset right before the
json.Unmarshal call that currently returns "failed to unmarshal from
unstructured".

---

Nitpick comments:
In `@bindings/go/runtime/registry_convert_test.go`:
- Around line 229-236: Add an assertion that raw.Type is populated after
converting the Unstructured to runtime.Raw: after calling scheme.Convert(un,
raw) (and require.NoError), assert that raw.Type equals the expected typ (the
same variable used later) to catch regressions in Raw.UnmarshalJSON; reference
runtime.Raw, scheme.Convert and Raw.UnmarshalJSON and place the check before
unmarshalling raw.Data into TestType.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 591e3907-db1b-44e6-b503-03d24d55f77d

📥 Commits

Reviewing files that changed from the base of the PR and between 3041eaf and 6309a5d.

📒 Files selected for processing (4)
  • bindings/go/runtime/registry.go
  • bindings/go/runtime/registry_convert_test.go
  • bindings/go/runtime/unstructured.go
  • bindings/go/runtime/unstructured_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • bindings/go/runtime/unstructured_test.go

Comment thread bindings/go/runtime/registry.go Outdated
@matthiasbruns matthiasbruns force-pushed the fix/unstructured_type_handling branch from 4cb2046 to 0b325ba Compare March 12, 2026 13:34
@github-actions github-actions Bot added the size/l Large label Mar 12, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
bindings/go/runtime/registry.go (1)

415-421: ⚠️ Potential issue | 🟠 Major

Reset the destination before JSON decode.

Both decode helpers still call json.Unmarshal on the existing target, so a reused into can retain omitted struct fields or map keys from a previous conversion. That makes Raw -> Typed and Unstructured -> Typed behave like patches instead of replacements.

💡 Suggested fix
 func (r *Scheme) convertFromRaw(from *Raw, into Typed, fromType Type) error {
 	// Raw → Raw: Deep copy the underlying data.
 	if rawInto, ok := into.(*Raw); ok {
 		from.DeepCopyInto(rawInto)
 		return nil
 	}

 	// Raw → Typed: Unmarshal the Raw.Data into the target.
 	if !r.IsRegistered(fromType) && !r.allowUnknown {
 		return fmt.Errorf("cannot decode from unregistered type: %s", fromType)
 	}
+	intoVal := reflect.ValueOf(into)
+	if intoVal.Kind() != reflect.Ptr || intoVal.IsNil() {
+		return fmt.Errorf("'into' must be a non-nil pointer")
+	}
+	intoVal.Elem().Set(reflect.Zero(intoVal.Elem().Type()))
 	if err := json.Unmarshal(from.Data, into); err != nil {
 		return fmt.Errorf("failed to unmarshal from raw: %w", err)
 	}
 	return nil
 }
@@
 	data, err := json.Marshal(from.Data)
 	if err != nil {
 		return fmt.Errorf("failed to marshal unstructured data: %w", err)
 	}
+	intoVal := reflect.ValueOf(into)
+	if intoVal.Kind() != reflect.Ptr || intoVal.IsNil() {
+		return fmt.Errorf("'into' must be a non-nil pointer")
+	}
+	intoVal.Elem().Set(reflect.Zero(intoVal.Elem().Type()))
 	if err := json.Unmarshal(data, into); err != nil {
 		return fmt.Errorf("failed to unmarshal from unstructured: %w", err)
 	}
In Go's encoding/json package, when json.Unmarshal decodes into a non-zero struct or map, do omitted struct fields and pre-existing map keys remain unchanged?

Also applies to: 433-442

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/registry.go` around lines 415 - 421, The decode path that
does "json.Unmarshal(from.Data, into)" can leave previous values in the target
when reused; before calling json.Unmarshal in the Raw -> Typed block (the code
using variables from/into and the r.allowUnknown check) and the analogous
Unstructured -> Typed section, reset the destination pointed to by into to its
zero value via reflection (handle pointers by dereferencing/allocating as
needed, and clear maps/slices) so json.Unmarshal writes a fresh value rather
than merging with prior contents. Ensure you use reflect to set into to
reflect.Zero(reflect.TypeOf(...)) or recreate the pointed value for
pointer-to-struct/map/slice cases before calling json.Unmarshal.
🧹 Nitpick comments (2)
bindings/go/runtime/registry_convert_test.go (1)

373-387: Assert the parsed type in the allowUnknown case.

This test currently only checks Foo, so it would still pass if the conversion started dropping or zeroing the unknown Type value. Since this PR is about type handling, it is worth locking that in explicitly.

✅ Suggested test tightening
 func TestConvert_UnstructuredToTyped_AllowUnknown(t *testing.T) {
 	scheme := runtime.NewScheme(runtime.WithAllowUnknown())
+	typ := runtime.NewVersionedType("UnknownType", "v1")

 	un := &runtime.Unstructured{
 		Data: map[string]any{
-			"type": "UnknownType/v1",
+			"type": typ.String(),
 			"foo":  "bar",
 		},
 	}

 	out := &TestType{}
 	err := scheme.Convert(un, out)
 	require.NoError(t, err)
 	assert.Equal(t, "bar", out.Foo)
+	assert.Equal(t, typ, out.Type)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/registry_convert_test.go` around lines 373 - 387, The
test TestConvert_UnstructuredToTyped_AllowUnknown only asserts out.Foo; add an
assertion that the converted object's type field is preserved by checking the
TestType instance (out) has its Type (or equivalent type-identifying field)
equal to the original "UnknownType/v1" after scheme.Convert; update the
assertions in the test to require no error and assert both out.Foo == "bar" and
out.Type == "UnknownType/v1" (use the actual field name on TestType).
bindings/go/runtime/registry.go (1)

361-367: Update the conversion comments to match the refactor.

The public Convert doc still omits Unstructured -> Raw and still scopes registration failures to Raw conversions, and convertFromTyped still says it returns a boolean even though it now returns only error.

📝 Suggested wording update
 // Special Cases:
 //   - Raw → Raw: performs a deep copy of the underlying []byte data.
 //   - Raw → Typed: unmarshals Raw.Data JSON via json.Unmarshal into the Typed object (if Typed.GetType is registered).
 //   - Typed → Raw: marshals the Typed with json.Marshal, applies canonicalization, and stores the result in Raw.Data.
 //     (See Raw.UnmarshalJSON for equivalent behavior)
+//   - Unstructured → Raw: marshals the Unstructured, applies canonicalization, and stores the result in Raw.Data.
 //   - Unstructured → Typed: marshals the Unstructured.Data to JSON and then unmarshals it into the Typed object (if Typed.GetType is registered).
 //   - Typed → Typed: performs a deep copy using Typed.DeepCopyTyped, with reflection-based assignment.
 //
 // Errors are returned if:
 //   - Either argument is nil.
-//   - A type is not registered in the Scheme (for Raw conversions).
+//   - A source type is not registered in the Scheme for Raw/Unstructured conversions.
 //   - A reflection-based assignment fails due to type mismatch.
@@
-// It returns a boolean indicating whether the conversion was handled, and an error if the conversion failed.
+// It returns an error if the conversion fails.

Also applies to: 448-452

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/registry.go` around lines 361 - 367, Update the public
Convert doc comment and related docs to reflect the refactor: explicitly
document the Unstructured → Raw conversion path (marshals Unstructured.Data to
JSON and stores it in Raw.Raw) in addition to Unstructured→Typed, Typed→Typed,
and Raw→Typed; remove the incorrect statement that registration failures are
limited to Raw conversions and instead state when Scheme registration is
required (e.g., any conversion that needs to instantiate or marshal/unmarshal a
Typed type); and update the convertFromTyped comment to remove the obsolete
"returns a boolean" note and state it now returns only error. Reference the
Convert function and convertFromTyped helper in registry.go when applying these
wording changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@bindings/go/runtime/registry.go`:
- Around line 415-421: The decode path that does "json.Unmarshal(from.Data,
into)" can leave previous values in the target when reused; before calling
json.Unmarshal in the Raw -> Typed block (the code using variables from/into and
the r.allowUnknown check) and the analogous Unstructured -> Typed section, reset
the destination pointed to by into to its zero value via reflection (handle
pointers by dereferencing/allocating as needed, and clear maps/slices) so
json.Unmarshal writes a fresh value rather than merging with prior contents.
Ensure you use reflect to set into to reflect.Zero(reflect.TypeOf(...)) or
recreate the pointed value for pointer-to-struct/map/slice cases before calling
json.Unmarshal.

---

Nitpick comments:
In `@bindings/go/runtime/registry_convert_test.go`:
- Around line 373-387: The test TestConvert_UnstructuredToTyped_AllowUnknown
only asserts out.Foo; add an assertion that the converted object's type field is
preserved by checking the TestType instance (out) has its Type (or equivalent
type-identifying field) equal to the original "UnknownType/v1" after
scheme.Convert; update the assertions in the test to require no error and assert
both out.Foo == "bar" and out.Type == "UnknownType/v1" (use the actual field
name on TestType).

In `@bindings/go/runtime/registry.go`:
- Around line 361-367: Update the public Convert doc comment and related docs to
reflect the refactor: explicitly document the Unstructured → Raw conversion path
(marshals Unstructured.Data to JSON and stores it in Raw.Raw) in addition to
Unstructured→Typed, Typed→Typed, and Raw→Typed; remove the incorrect statement
that registration failures are limited to Raw conversions and instead state when
Scheme registration is required (e.g., any conversion that needs to instantiate
or marshal/unmarshal a Typed type); and update the convertFromTyped comment to
remove the obsolete "returns a boolean" note and state it now returns only
error. Reference the Convert function and convertFromTyped helper in registry.go
when applying these wording changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c660ca86-9985-4fb2-a58d-793fdd07d1a4

📥 Commits

Reviewing files that changed from the base of the PR and between 6309a5d and 4cb2046.

📒 Files selected for processing (2)
  • bindings/go/runtime/registry.go
  • bindings/go/runtime/registry_convert_test.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
bindings/go/runtime/registry.go (1)

408-422: Consider the merge behavior of json.Unmarshal for reused destinations.

As discussed in past reviews, json.Unmarshal merges into existing values rather than replacing them. If a caller reuses a destination struct that already has fields set, fields not present in the source JSON will retain their old values. This is a minor concern if callers always pass freshly allocated destinations, but could cause subtle bugs if destinations are reused.

If full replacement semantics are desired, consider zeroing the destination before unmarshaling:

intoVal := reflect.ValueOf(into)
intoVal.Elem().Set(reflect.Zero(intoVal.Elem().Type()))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/registry.go` around lines 408 - 422, The convertFromRaw
method on Scheme currently calls json.Unmarshal(into) which will merge into a
reused destination rather than replace it; to ensure full replacement semantics,
zero the destination before unmarshaling (for the Raw → Typed branch) by
obtaining reflect.ValueOf(into), calling
Elem().Set(reflect.Zero(Elem().Type())), then proceed with json.Unmarshal;
update convertFromRaw (symbols: Scheme.convertFromRaw, Raw, Typed, fromType,
r.allowUnknown, json.Unmarshal, into) to perform this zeroing step so reused
destination structs do not retain stale fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@bindings/go/runtime/registry.go`:
- Around line 408-422: The convertFromRaw method on Scheme currently calls
json.Unmarshal(into) which will merge into a reused destination rather than
replace it; to ensure full replacement semantics, zero the destination before
unmarshaling (for the Raw → Typed branch) by obtaining reflect.ValueOf(into),
calling Elem().Set(reflect.Zero(Elem().Type())), then proceed with
json.Unmarshal; update convertFromRaw (symbols: Scheme.convertFromRaw, Raw,
Typed, fromType, r.allowUnknown, json.Unmarshal, into) to perform this zeroing
step so reused destination structs do not retain stale fields.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b6b29971-50f7-4c19-8757-9836cde00905

📥 Commits

Reviewing files that changed from the base of the PR and between 4cb2046 and 0b325ba.

📒 Files selected for processing (2)
  • bindings/go/runtime/registry.go
  • bindings/go/runtime/registry_convert_test.go

@matthiasbruns matthiasbruns force-pushed the fix/unstructured_type_handling branch from 0b325ba to 1b9d113 Compare March 12, 2026 14:01
@matthiasbruns matthiasbruns force-pushed the fix/unstructured_type_handling branch 2 times, most recently from 0e5aea0 to f4750bf Compare March 12, 2026 14:12
@matthiasbruns

matthiasbruns commented Mar 12, 2026

Copy link
Copy Markdown
Contributor Author

open-component-model/ocm-project#944 - follow up task to tackle Unstructured in Scheme.Convert correctly

@matthiasbruns matthiasbruns force-pushed the fix/unstructured_type_handling branch from f4750bf to d2b549e Compare March 12, 2026 14:19
On-behalf-of: SAP <matthias.bruns@sap.com>
Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
@matthiasbruns matthiasbruns force-pushed the fix/unstructured_type_handling branch from d2b549e to ed9b968 Compare March 12, 2026 14:21

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
bindings/go/runtime/unstructured_test.go (1)

200-204: Test case name is misleading.

The name states "falls back to unversioned" but the expected value is runtime.Type{} (a zero value), not an unversioned type. An unversioned type would have a non-empty Name. Consider renaming for clarity.

Suggested name fix
 {
-    name:     "invalid string with too many segments falls back to unversioned",
+    name:     "invalid string with too many segments returns zero Type",
     data:     map[string]any{"type": "some/invalid/type"},
     expected: runtime.Type{},
 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/go/runtime/unstructured_test.go` around lines 200 - 204, The test
case name "invalid string with too many segments falls back to unversioned" is
misleading because the expected value is runtime.Type{} (zero value) not an
unversioned type with a Name; update the test case's name field (the map entry
with name: "invalid string with too many segments falls back to unversioned") to
reflect that it expects a zero/invalid Type (suggestions: "invalid string with
too many segments yields zero Type" or "invalid string with too many segments ->
zero value Type"), leaving the data and expected runtime.Type{} unchanged so the
test intent is clear.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@bindings/go/runtime/unstructured_test.go`:
- Around line 200-204: The test case name "invalid string with too many segments
falls back to unversioned" is misleading because the expected value is
runtime.Type{} (zero value) not an unversioned type with a Name; update the test
case's name field (the map entry with name: "invalid string with too many
segments falls back to unversioned") to reflect that it expects a zero/invalid
Type (suggestions: "invalid string with too many segments yields zero Type" or
"invalid string with too many segments -> zero value Type"), leaving the data
and expected runtime.Type{} unchanged so the test intent is clear.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1a5a7cf3-7082-4a13-9f86-f5e5e1f4745c

📥 Commits

Reviewing files that changed from the base of the PR and between 0b325ba and ed9b968.

📒 Files selected for processing (2)
  • bindings/go/runtime/unstructured.go
  • bindings/go/runtime/unstructured_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • bindings/go/runtime/unstructured.go

@matthiasbruns matthiasbruns enabled auto-merge (squash) March 12, 2026 15:31
@matthiasbruns matthiasbruns merged commit 9b60a41 into open-component-model:main Mar 13, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor toOCI() function available in cel to deal with oci and localblob

3 participants