Skip to content

Conversation

@chrischdi
Copy link
Contributor

@chrischdi chrischdi commented Oct 10, 2025

Summary by CodeRabbit

  • Refactor
    • Replaced ad-hoc map diffs with a unified, platform-aware diff result, enabling per-block Has* checks, clearer gating of spec/status updates, and consistent error propagation across reconciliation flows.
  • New Features
    • Added a configurable differ with providerSpec extraction, public DiffResult interface, providerSpec conversion helper, and deterministic ordering for platform-specific data.
  • Tests
    • Added comprehensive unit tests and test-suite scaffolding for diff behavior, lists, conditions, and LastTransitionTime handling.
  • Chores
    • Removed legacy map-based comparison helpers and external deep-diff dependency.

✏️ Tip: You can customize this high-level summary in your review settings.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Oct 10, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 10, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Oct 10, 2025
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Oct 10, 2025

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@coderabbitai
Copy link

coderabbitai bot commented Oct 10, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'path_filters'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Replaces ad-hoc map-based diffs with a unified pkg/util differ returning a DiffResult; makes providerSpec handling platform-aware and deterministic; updates many compare/ensure/update function signatures and call sites across machine and machineset controllers; removes legacy deep-based helpers and adds tests for the new differ.

Changes

Cohort / File(s) Summary
Diff Utility Implementation
pkg/util/diff.go
Adds a pluggable differ and public DiffResult interface with HasChanges/HasMetadataChanges/HasSpecChanges/HasProviderSpecChanges/HasStatusChanges; supports ignore paths, LastTransitionTime ignoring, providerSpec extraction, and deterministic per-top-level-key diffs.
Diff Tests & Suite
pkg/util/diff_test.go, pkg/util/suite_test.go
Adds Ginkgo/Gomega tests and a test suite entry validating differ behavior, HasChanges, and string output.
MachineSet Sync Controller
pkg/controllers/machinesetsync/machineset_sync_controller.go, pkg/controllers/machinesetsync/machineset_sync_controller_test.go, pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go
Replaces map-based diffs with util.DiffResult for CAPI/MAPI MachineSets and infra templates; compare functions become platform-aware; ensure*/status methods accept DiffResult and use Has* checks; tests updated and new unit tests added.
Machine Sync Controller
pkg/controllers/machinesync/machine_sync_controller.go, pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go
compareCAPIMachines/compareMAPIMachines and related ensure/update functions now use (util.DiffResult, error) and platform-aware providerSpec diffing; call sites updated; deep-based helpers and imports removed; minor rename fix for validateMAPIToCAPIPlatformSpecifics.
Sync Helpers Removed
pkg/util/sync.go
Removes legacy specialized comparison helpers and condition comparators; drops dependency on github.com/go-test/deep.
ProviderSpec Conversion
pkg/conversion/mapi2capi/util.go
Adds ProviderSpecFromRawExtension(platform, rawExtension) with platform dispatch (AWS implemented) and a sentinel error errUnsupportedPlatform.
Provider Determinism Fixes
pkg/conversion/mapi2capi/aws.go, pkg/conversion/mapi2capi/openstack.go
Adds deterministic sorting (AWS Tags, OpenStack metadata) after unmarshalling to ensure stable conversions.
Controller Tests & Contexts
pkg/controllers/machinesync/machine_sync_controller_test.go, pkg/controllers/machinesetsync/*_test.go
Tests updated to new platform-aware signatures and DiffResult API; new MAPI sync test contexts and machineset unit tests added/adjusted.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Reconciler
  participant Converter
  participant Differ as "pkg/util differ"
  participant API as "K8s API"

  Reconciler->>Converter: build converted object (CAPI/MAPI)
  Reconciler->>Differ: diffResult, err = Diff(existing, converted)
  alt Diff error
    Differ-->>Reconciler: error
    Reconciler->>API: record/surface error
  else Diff computed
    Differ-->>Reconciler: DiffResult (HasChanges, HasSpec/Meta/Status/ProviderSpec)
    alt Spec/Metadata/ProviderSpec changes
      Reconciler->>API: patch/update spec/metadata
    end
    alt Status changes (observedGeneration guard)
      Reconciler->>API: patch/update status
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Review focus:
    • ProviderSpec extraction plumbing and platform dispatch (WithProviderSpec + ProviderSpecFromRawExtension).
    • removeConditionsLastTransitionTime and ignore rules across API versions.
    • All updated function signatures and call sites to ensure no remaining map[string]any assumptions.
    • Deterministic diff string formatting and AWS/OpenStack sorting changes.
    • New/updated tests for correctness and flakiness.

Poem

🐰 I hopped through fields both old and new,
I turned loose maps into a structured view.
I hushed the times that softly sway,
I sorted tags so diffs would stay.
A rabbit's patch — tidy, true, and few.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main refactoring effort: replacing legacy map-based diffs with a generalized, type-independent differ system, which is the primary focus of all changes across the codebase.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between d2ce231 and d87410b.

📒 Files selected for processing (3)
  • pkg/controllers/machinesync/machine_sync_controller.go (9 hunks)
  • pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (9 hunks)
  • pkg/util/diff.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/util/diff.go
🔇 Additional comments (12)
pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (4)

32-32: LGTM: Import addition is necessary.

The clusterv1 import is correctly added to support the clusterv1.PausedV1Beta2Condition constant used in the differ configuration.


67-67: LGTM: Function signature updates are consistent.

The migration from map-based diffs to util.DiffResult with per-block checking methods (HasSpecChanges(), HasMetadataChanges(), HasStatusChanges()) is implemented correctly across all call sites.

Also applies to: 76-76, 125-125, 129-129, 150-150, 154-154


88-90: LGTM: Log message clarification.

The log messages now consistently refer to "Cluster API Infrastructure machine" which improves clarity and distinguishes from CAPI Machine objects.


249-305: LGTM: Refactored differ implementation is clean and consistent.

The migration to util.NewDefaultDiffer() simplifies the comparison logic while maintaining platform-specific type handling. The configuration correctly ignores PausedV1Beta2Condition since it's managed by CAPI controllers.

pkg/controllers/machinesync/machine_sync_controller.go (8)

484-484: LGTM: Typo correction in function name.

The function name has been corrected from validateMAPIToCAPIPlatfromSpecifics to validateMAPIToCAPIPlatformSpecifics. Both the definition and call site are properly updated.

Also applies to: 600-608


679-705: LGTM: CAPI machine spec update logic is correct.

The function correctly uses HasMetadataChanges() and HasSpecChanges() for CAPI machines. Note that HasProviderSpecChanges() is not checked here, which is appropriate since CAPI machines use InfrastructureRef rather than an embedded providerSpec.


728-731: LGTM: Error handling added for compare operation.

The error handling for compareCAPIMachines is correctly implemented with proper error wrapping and propagation.


782-785: LGTM: Platform parameter correctly added.

The compareMAPIMachines call now correctly passes the platform parameter to enable platform-aware providerSpec diffing.


1295-1305: LGTM: Simplified CAPI machine comparison.

The refactored compareCAPIMachines function cleanly leverages the unified differ and correctly ignores the PausedV1Beta2Condition which is managed by CAPI controllers.


1308-1325: LGTM: Platform-aware MAPI machine comparison is well-configured.

The differ configuration correctly:

  • Extracts and compares platform-specific providerSpecs using the path ["spec", "providerSpec", "value"]
  • Ignores MAPI-specific status fields managed by other controllers (providerStatus, lastOperation, authoritativeAPI, synchronizedGeneration)
  • Ignores the Synchronized condition managed by the migration controller

1328-1377: LGTM: CAPI machine status update logic is sound.

The function correctly uses HasStatusChanges() and preserves the generation observation guard to ensure the MAPI machine status has caught up before updating CAPI status.


1409-1454: LGTM: MAPI machine update logic correctly handles providerSpec.

Both functions properly use the per-block diff methods:

  • ensureMAPIMachineStatusUpdated checks HasStatusChanges()
  • ensureMAPIMachineSpecUpdated checks HasMetadataChanges(), HasSpecChanges(), and HasProviderSpecChanges()

Note that HasProviderSpecChanges() is correctly checked for MAPI machines (which have embedded providerSpecs) but not for CAPI machines (which use InfrastructureRef).

Also applies to: 1457-1480

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

@chrischdi
Copy link
Contributor Author

/test unit
/test lint
/test build

Copy link
Contributor

@mdbooth mdbooth left a comment

Choose a reason for hiding this comment

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

I think this is great and a clear improvement. I have some follow-on ideas, but I would personally gladly merge this and iterate on it in the unlikely event it ever became worth it.

I shared a thought inline based on something similar we did in ORC with field indexers.

Not at all important, but I also feel that Unstructured is an internal implementation detail: e.g. the Diff method could be implemented with reflection and the signature would not change.

pkg/util/sync.go Outdated
Comment on lines 93 to 100
differ := UnstructuredDiffer[clusterv1.MachineSetStatus]{
customDiff: []func(a clusterv1.MachineSetStatus, b clusterv1.MachineSetStatus) ([]string, error){
func(a, b clusterv1.MachineSetStatus) ([]string, error) {
return compareCAPIMachineSetConditions(a.Conditions, b.Conditions), nil
},
},
ignoreFields: [][]string{{"conditions"}},
}
Copy link
Contributor

Choose a reason for hiding this comment

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

differ := UnstructuredDiffer[clusterv1.MachineSetStatus]()

differ = WithCustomDiff(differ,
    "conditions",
    func(x *clusterv1.MachineSetStatus) []clusterv1.Condition {return x.conditions},
    compareCAPIConditions)

func compareCAPIConditions(a, b []clusterv1.Conditions) []string {
    ...
}

WithCustomDiff unfortunately can't be a method on UnstructuredDiffer as it has an additional type argument([]clusterv1.Condition).

Advantages of this approach:

  • ignoreField is a required argument of CustomDiff, removing a footgun
  • compareCAPIConditions is now reusable by all types with CAPI conditions

Disadvantages:

  • The argument to pull a field out is a bit ugly

Copy link
Contributor

Choose a reason for hiding this comment

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

ignoreField is a required argument of CustomDiff, removing a footgun

Are there cases when we want to ignore fields without custom diffs no? Maybe around deprecated fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes there are (e.g. CAPI's conversion-data annotation).

However I'd combine it, but keeping the option to ignore paths completely:

	differ := NewUnstructuredDiffer(
		WithCustomDiff([]string{"conditions"}, func(a, b clusterv1.MachineSetStatus) ([]string, error) {
			return compareCAPIV1Beta1Conditions(a.Conditions, b.Conditions), nil
		}),
		WithCustomDiff([]string{"v1beta2", "conditions"}, func(a, b clusterv1.MachineSetStatus) ([]string, error) {
			return compareCAPIV1Beta2Conditions(
					ptr.Deref(a.V1Beta2, clusterv1.MachineSetV1Beta2Status{}).Conditions,
					ptr.Deref(b.V1Beta2, clusterv1.MachineSetV1Beta2Status{}).Conditions),
				nil
		}),
		WithIgnoreField[clusterv1.MachineSetStatus]("conditions", "bar"),
	)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored, don't have the "WithCustomDiff" anymore.
I now have an option for the conditions part instead.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 10, 2025
pkg/util/diff.go Outdated
"k8s.io/apimachinery/pkg/runtime"
)

type UnstructuredDiffer[T any] struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

If this is unstructured, why is it also generic? Does it make this simpler than using runtime.Object for the a, b arguments?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed just to differ. Should work for any struct.

pkg/util/diff.go Outdated

diff := deep.Equal(unstructuredA, unstructuredB)
if len(diff) > 0 {
diffs["deep.Equal"] = diff
Copy link
Contributor

Choose a reason for hiding this comment

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

Why the deep.Equal key? Does this get exposed to end users? Is this a magic word?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not there anymore :-)

pkg/util/sync.go Outdated
Comment on lines 85 to 91
// Maybe we can also have it this way:
// differ := NewUnstructuredDiffer(
// WithIgnoreField[clusterv1.MachineSetStatus]("conditions"),
// WithCustomDiff(func(a, b clusterv1.MachineSetStatus) ([]string, error) {
// return compareCAPIMachineSetConditions(a.Conditions, b.Conditions), nil
// }),
// )
Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored :-)

pkg/util/sync.go Outdated
Comment on lines 93 to 100
differ := UnstructuredDiffer[clusterv1.MachineSetStatus]{
customDiff: []func(a clusterv1.MachineSetStatus, b clusterv1.MachineSetStatus) ([]string, error){
func(a, b clusterv1.MachineSetStatus) ([]string, error) {
return compareCAPIMachineSetConditions(a.Conditions, b.Conditions), nil
},
},
ignoreFields: [][]string{{"conditions"}},
}
Copy link
Contributor

Choose a reason for hiding this comment

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

ignoreField is a required argument of CustomDiff, removing a footgun

Are there cases when we want to ignore fields without custom diffs no? Maybe around deprecated fields?

@chrischdi chrischdi force-pushed the pr-sync-refactor-how-to-diff branch from ac815fd to f494b0c Compare October 30, 2025 17:34
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 30, 2025
@chrischdi chrischdi marked this pull request as ready for review October 30, 2025 17:34
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Oct 30, 2025
@openshift-ci openshift-ci bot requested review from damdo and nrb October 30, 2025 17:34
@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 30, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Summary by CodeRabbit

Release Notes

  • Refactor

  • Improved resource comparison logic across machine synchronization controllers with structured, field-by-field analysis

  • Enhanced platform-aware handling for infrastructure resources across supported cloud platforms

  • Bug Fixes

  • Added proper error handling and reporting in resource synchronization comparison operations to surface issues previously undetected

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Comment on lines 1381 to 1400
// Compare metadata
if diffMetadata, err := util.ObjectMetaEqual(metadata1, metadata2); err != nil {
return nil, fmt.Errorf("failed to compare Cluster API Infrastructure machine metadata: %w", err)
} else if diffMetadata.Changed() {
diff[".metadata"] = diffMetadata.String()
}

// TODO: Evaluate if we want to add status comparison if needed in the future (e.g. for scale from zero capacity).
// Compare spec
if diffSpec, err := util.NewDiffer().Diff(spec1, spec2); err != nil {
return nil, fmt.Errorf("failed to compare Cluster API Infrastructure machine spec: %w", err)
} else if diffSpec.Changed() {
diff[".spec"] = diffSpec.String()
}

return diff, nil
default:
return nil, fmt.Errorf("%w: %s", errPlatformNotSupported, platform)
// Compare status
if diffStatus, err := util.NewDiffer(util.WithIgnoreConditionsLastTransitionTime()).Diff(status1, status2); err != nil {
return nil, fmt.Errorf("failed to compare Cluster API Infrastructure machine status: %w", err)
} else if diffStatus.Changed() {
diff[".status"] = diffStatus.String()
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm thinking about doing this even more generic, as this is the same across the codebase.

Copy link
Contributor

Choose a reason for hiding this comment

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

More generic as in abstracting each of the diff fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope, updated the PR. We now don't have to distinct and manually do the diff for metadata, spec, status.

We always compare the whole object and can have all results:

...Diff(clusterv1.Machine, clusterv1.Machine)

:-)

Comment on lines 1343 to 1344
status1 = typedInfraMachineTemplate1.Status
status2 = typedinfraMachineTemplate2.Status
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: added status conversion here.

Let's see if we break something or not :-)

Copy link

@coderabbitai coderabbitai bot left a comment

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)
pkg/controllers/machinesetsync/machineset_sync_controller.go (1)

1346-1354: Return the correct OpenStack assertion error.

In the OpenStack branch we still return errAssertingCAPIIBMPowerVSMachineTemplate on a type mismatch. Callers that rely on errors.Is(..., errAssertingCAPIOpenStackMachineTemplate) will now miss this case, breaking platform-specific handling. Please swap the constant to the OpenStack one for both checks in this branch.

-		typedInfraMachineTemplate1, ok := infraMachineTemplate1.(*openstackv1.OpenStackMachineTemplate)
-		if !ok {
-			return nil, errAssertingCAPIIBMPowerVSMachineTemplate
-		}
+		typedInfraMachineTemplate1, ok := infraMachineTemplate1.(*openstackv1.OpenStackMachineTemplate)
+		if !ok {
+			return nil, errAssertingCAPIOpenStackMachineTemplate
+		}

 		typedinfraMachineTemplate2, ok := infraMachineTemplate2.(*openstackv1.OpenStackMachineTemplate)
 		if !ok {
 			return nil, errAssertingCAPIOpenStackMachineTemplate
 		}
🧹 Nitpick comments (2)
pkg/util/sync_test.go (1)

332-341: Assert the string output even for unchanged diffs
Right now we skip got.String() comparisons when tt.wantChanges is false, so a future regression where Changed() returns false but String() leaks content would slide through. Consider moving the g.Expect(got.String()).To(Equal(tt.want)) assertion outside the conditional (the happy-path cases already set want to ""), or duplicating it in the else. That keeps the test guarding both facets of the contract.

pkg/controllers/machinesync/machine_sync_controller.go (1)

1259-1277: Tighten the error message wording
These error strings still say “Cluster API Infrastructure machine …” even though this helper compares the top-level CAPI Machine. Tweaking the wording here (and in the similar spec/status branches) would make logs clearer when we do hit this path.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a395cf1 and f494b0c.

📒 Files selected for processing (7)
  • pkg/controllers/machinesetsync/machineset_sync_controller.go (6 hunks)
  • pkg/controllers/machinesync/machine_sync_controller.go (3 hunks)
  • pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (5 hunks)
  • pkg/util/diff.go (1 hunks)
  • pkg/util/diff_test.go (1 hunks)
  • pkg/util/sync.go (1 hunks)
  • pkg/util/sync_test.go (1 hunks)
🔇 Additional comments (1)
pkg/util/diff_test.go (1)

78-115: Nice coverage for slice diffs
Exercising add/remove/change scenarios on list fields gives strong confidence that the new differ is handling positional data correctly. Thanks for including these cases.

Comment on lines 1381 to 1400
// Compare metadata
if diffMetadata, err := util.ObjectMetaEqual(metadata1, metadata2); err != nil {
return nil, fmt.Errorf("failed to compare Cluster API Infrastructure machine metadata: %w", err)
} else if diffMetadata.Changed() {
diff[".metadata"] = diffMetadata.String()
}

// TODO: Evaluate if we want to add status comparison if needed in the future (e.g. for scale from zero capacity).
// Compare spec
if diffSpec, err := util.NewDiffer().Diff(spec1, spec2); err != nil {
return nil, fmt.Errorf("failed to compare Cluster API Infrastructure machine spec: %w", err)
} else if diffSpec.Changed() {
diff[".spec"] = diffSpec.String()
}

return diff, nil
default:
return nil, fmt.Errorf("%w: %s", errPlatformNotSupported, platform)
// Compare status
if diffStatus, err := util.NewDiffer(util.WithIgnoreConditionsLastTransitionTime()).Diff(status1, status2); err != nil {
return nil, fmt.Errorf("failed to compare Cluster API Infrastructure machine status: %w", err)
} else if diffStatus.Changed() {
diff[".status"] = diffStatus.String()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

More generic as in abstracting each of the diff fields?


out := "." + strings.Join(d.diff, ", .")
out = strings.ReplaceAll(out, ".slice[", "[")
out = strings.ReplaceAll(out, "map[", "[")
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be a nit, but could we distinguish maps from slices with {}? Might be too much work, since we'd have to find and replace the closing characters, but it could be helpful in interpreting output.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is pure cosmetics / output (I guess mostly for us when debugging).

I'm even okay with keeping the more verbose mode.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Examples:

Input:

	a := &awsv1.AWSMachine{
		Spec: awsv1.AWSMachineSpec{
			ProviderID: ptr.To("before-change"),
			InstanceID: ptr.To("removed"),
			// ImageLookupOrg: "added",
		},
	}

	b := &awsv1.AWSMachine{
		Spec: awsv1.AWSMachineSpec{
			ProviderID:     ptr.To("after-change"),
			// InstanceID: ptr.To("removed"),
			ImageLookupOrg: "added",
		},
	}

Before:

[Spec.ProviderID: after-change != before-change Spec.InstanceID: <nil pointer> != string Spec.ImageLookupOrg: added != ]

After:

.[spec].[imageLookupOrg]: added != <does not have key>, .[spec].[instanceID]: <does not have key> != removed, .[spec].[providerID]: after-change != before-change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Main reason why I did the [] thing was e.g. label keys, because they have dots.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 31, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Summary by CodeRabbit

  • Refactor

  • Improved machine synchronization comparison logic with enhanced error handling and deterministic diff detection across controllers

  • Replaced legacy comparison mechanisms with a unified, structured approach for more reliable change detection

  • Tests

  • Added comprehensive unit tests for differential comparison functionality

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 31, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Summary by CodeRabbit

Release Notes

  • Refactor
  • Improved machine and machineset synchronization with structured diff handling, enabling more granular change detection and better error propagation across comparison operations.
  • Removed external dependency (go-test/deep) and consolidated diffing utilities for cleaner internal architecture.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
pkg/util/diff.go (1)

126-134: Don't wrap the operands in & before converting to unstructured.

runtime.DefaultUnstructuredConverter.ToUnstructured expects the actual object. Passing &a / &b hands it *client.Object, so every diff on typed resources fails. While fixing that, please correct the first error message so it references “a”.

-	unstructuredA, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&a)
-	if err != nil {
-		return nil, fmt.Errorf("failed to convert b to unstructured: %w", err)
+	unstructuredA, err := runtime.DefaultUnstructuredConverter.ToUnstructured(a)
+	if err != nil {
+		return nil, fmt.Errorf("failed to convert a to unstructured: %w", err)
 	}

-	unstructuredB, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&b)
+	unstructuredB, err := runtime.DefaultUnstructuredConverter.ToUnstructured(b)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between f494b0c and e0114e3.

📒 Files selected for processing (9)
  • pkg/controllers/machinesetsync/machineset_sync_controller.go (11 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_test.go (1 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go (1 hunks)
  • pkg/controllers/machinesync/machine_sync_controller.go (6 hunks)
  • pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (7 hunks)
  • pkg/conversion/mapi2capi/util.go (1 hunks)
  • pkg/util/diff.go (1 hunks)
  • pkg/util/diff_test.go (1 hunks)
  • pkg/util/sync.go (0 hunks)
💤 Files with no reviewable changes (1)
  • pkg/util/sync.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/util/diff_test.go
🔇 Additional comments (13)
pkg/conversion/mapi2capi/util.go (1)

44-49: Deterministic tag ordering looks great.

Sorting the AWS tags up front eliminates noisy diffs when we convert back and forth between map and slice representations.

pkg/controllers/machinesetsync/machineset_sync_controller_test.go (1)

1177-1188: Thanks for exercising the new diff surface.

Checking HasProviderSpecChanges() and HasChanges() here makes sure the platform-aware comparer behaves correctly.

pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go (1)

31-351: Great coverage for DiffResult behaviour.

These table-driven cases hit all the tricky status paths—including the v1beta1/v1beta2 condition handling and LastTransitionTime suppression—so we can trust the refactored comparer.

pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (1)

63-82: DiffResult integration reads clean.

Branching on HasSpecChanges, HasMetadataChanges, and HasStatusChanges keeps the reconciliation flow explicit while reusing the shared differ.

pkg/controllers/machinesync/machine_sync_controller.go (5)

649-674: LGTM! Signature and logic updated correctly.

The function signature has been appropriately updated to accept util.DiffResult, and the conditional logic correctly uses the new Has*Changes() methods to determine if updates are needed.


697-700: LGTM! Error handling added correctly.

The comparison function now properly returns and propagates errors, improving robustness of the diff operation.


1254-1279: LGTM! Refactored comparison functions.

Both compareCAPIMachines and compareMAPIMachines have been properly refactored to:

  • Use the new util.NewDefaultDiffer() interface
  • Return structured util.DiffResult instead of maps
  • Propagate errors from diff computation
  • Support platform-aware provider spec comparison (MAPI machines)

The platform-aware diffing with WithProviderSpec and field ignore options in compareMAPIMachines is a solid improvement for handling provider-specific differences.


1282-1331: LGTM! Status update functions refactored correctly.

Both ensureCAPIMachineStatusUpdated and ensureMAPIMachineStatusUpdated have been consistently updated to accept util.DiffResult and use the HasStatusChanges() method for determining if status updates are needed.

Also applies to: 1363-1408


1411-1434: LGTM! Comprehensive change detection for MAPI machines.

The function correctly checks for metadata, spec, and provider spec changes, which is appropriate given that MAPI machines have provider-specific specifications that need to be tracked separately.

pkg/controllers/machinesetsync/machineset_sync_controller.go (4)

787-814: LGTM! Proper error handling for comparison.

The comparison function call correctly handles errors and propagates them with appropriate wrapping.


843-866: LGTM! All ensure functions refactored correctly.

All four ensure*Updated functions have been consistently updated to:

  • Accept util.DiffResult instead of map-based diffs
  • Use the appropriate Has*Changes() methods
  • Apply correct conditional logic with proper negation for early returns

Also applies to: 869-917, 920-944, 947-996


1021-1024: LGTM! Platform parameter added correctly.

The comparison function correctly receives the platform parameter to enable platform-aware provider spec diffing.


1317-1399: LGTM! Comparison functions properly refactored.

All three comparison functions have been successfully refactored to:

  • Return (util.DiffResult, error) instead of map-based diffs
  • Use util.NewDefaultDiffer() with appropriate configuration options
  • Handle platform-specific differences where needed (provider specs)
  • Properly wrap and propagate errors

The platform-aware diffing in compareCAPIInfraMachineTemplates and compareMAPIMachineSets with support for provider specs and field filtering is a significant improvement.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 31, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 31, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Summary by CodeRabbit

  • Refactor
  • Consolidated diffing into a unified, platform-aware differ for more reliable, deterministic change detection and improved error handling.
  • New Features
  • Added a reusable diff result interface with per-block change checks (metadata/spec/providerSpec/status).
  • Added providerSpec conversion support for platform-aware provider handling (AWS).
  • Tests
  • Added comprehensive unit tests covering diff behaviors and edge cases.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@chrischdi chrischdi force-pushed the pr-sync-refactor-how-to-diff branch from a9987c6 to dbbfcd3 Compare October 31, 2025 10:54
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 31, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 31, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Summary by CodeRabbit

  • Refactor
  • Consolidated diffing into a unified, platform-aware differ with per-block change checks and improved error propagation; removed legacy map-based diffs and external deep-equal dependency.
  • New Features
  • Introduced a reusable DiffResult interface (HasMetadata/Spec/ProviderSpec/Status) and platform-aware providerSpec handling.
  • Added ProviderSpec conversion for AWS.
  • Tests
  • Added unit tests covering diff behaviors, list/nested changes, and condition timestamp handling.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
pkg/controllers/machinesetsync/machineset_sync_controller.go (1)

742-745: Critical: Inverted condition prevents infrastructure template updates.

The condition is inverted: when HasChanges() returns true (changes exist), the code incorrectly logs "No changes detected" and returns early, preventing legitimate updates from being applied.

Apply this fix:

-	if capiInfraMachineTemplatesDiff.HasChanges() {
+	if !capiInfraMachineTemplatesDiff.HasChanges() {
 		logger.Info("No changes detected for CAPI infra machine template")
 		return nil
 	}
🧹 Nitpick comments (2)
pkg/conversion/mapi2capi/util.go (1)

33-53: Export the sentinel error so callers can detect unsupported platforms.

Because ProviderSpecFromRawExtension is exported, downstream callers will likely need to distinguish an unsupported platform from other parse failures. Keeping the sentinel unexported forces string matching; exporting it (e.g., ErrUnsupportedPlatform) lets clients rely on errors.Is. Please export the sentinel and update the reference accordingly.

-var errUnsupportedPlatform = errors.New("unsupported platform")
+var ErrUnsupportedPlatform = errors.New("unsupported platform")
...
-		return nil, fmt.Errorf("%w: %s", errUnsupportedPlatform, platform)
+		return nil, fmt.Errorf("%w: %s", ErrUnsupportedPlatform, platform)
pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (1)

248-301: LGTM: Platform-aware comparison successfully generalized.

The refactored comparison function correctly handles platform-specific type assertions before delegating to the type-agnostic differ. The error handling is comprehensive, and the default case ensures unsupported platforms are caught.

Optional: Consider renaming obj1 and obj2 to typedInfraMachine1 and typedInfraMachine2 for consistency with the parameter names and to make the type assertion flow clearer.

 func compareCAPIInfraMachines(platform configv1.PlatformType, infraMachine1, infraMachine2 client.Object) (util.DiffResult, error) {
-	var obj1, obj2 client.Object
+	var typedInfraMachine1, typedInfraMachine2 client.Object

 	switch platform {
 	case configv1.AWSPlatformType:
-		typedInfraMachine1, ok := infraMachine1.(*awsv1.AWSMachine)
+		awsMachine1, ok := infraMachine1.(*awsv1.AWSMachine)
 		if !ok {
 			return nil, errAssertingCAPIAWSMachine
 		}

-		typedinfraMachine2, ok := infraMachine2.(*awsv1.AWSMachine)
+		awsMachine2, ok := infraMachine2.(*awsv1.AWSMachine)
 		if !ok {
 			return nil, errAssertingCAPIAWSMachine
 		}

-		obj1 = typedInfraMachine1
-		obj2 = typedinfraMachine2
+		typedInfraMachine1 = awsMachine1
+		typedInfraMachine2 = awsMachine2
 	// ... similar for other platforms
 	}

-	diff, err := util.NewDefaultDiffer().Diff(obj1, obj2)
+	diff, err := util.NewDefaultDiffer().Diff(typedInfraMachine1, typedInfraMachine2)
 	if err != nil {
 		return nil, fmt.Errorf("failed to compare Cluster API infrastructure machines: %w", err)
 	}

 	return diff, nil
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a9987c6 and dbbfcd3.

📒 Files selected for processing (9)
  • pkg/controllers/machinesetsync/machineset_sync_controller.go (11 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_test.go (1 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go (1 hunks)
  • pkg/controllers/machinesync/machine_sync_controller.go (6 hunks)
  • pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (7 hunks)
  • pkg/conversion/mapi2capi/util.go (1 hunks)
  • pkg/util/diff.go (1 hunks)
  • pkg/util/diff_test.go (1 hunks)
  • pkg/util/sync.go (0 hunks)
💤 Files with no reviewable changes (1)
  • pkg/util/sync.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/util/diff_test.go
  • pkg/util/diff.go
🔇 Additional comments (20)
pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go (1)

30-351: Excellent test coverage for status diffing!

The comprehensive test suite effectively validates the new DiffResult-based diff approach across multiple scenarios:

  • Individual and combined field differences
  • v1beta1 and v1beta2 conditions handling
  • LastTransitionTime correctly ignored in comparisons
  • nil vs non-nil status scenarios

The test structure is clear and the assertions properly validate both HasChanges() and the diff string format.

pkg/controllers/machinesetsync/machineset_sync_controller_test.go (1)

1175-1189: Test updates correctly reflect new diff API.

The changes properly adapt to the platform-aware compareMAPIMachineSets signature and use the new DiffResult methods (HasProviderSpecChanges(), HasChanges()) instead of map-based checks.

pkg/controllers/machinesetsync/machineset_sync_controller.go (9)

787-790: Proper error handling for diff operation.

The updated signature correctly propagates errors from compareCAPIMachineSets, with appropriate error wrapping for context.


843-849: Clean integration with DiffResult API.

The function signature and logic correctly use the new DiffResult methods (HasMetadataChanges(), HasSpecChanges(), HasProviderSpecChanges()) to determine when spec updates are needed.


869-875: Correct status update gating logic.

The function properly uses HasStatusChanges() and the specUpdated flag to determine when status updates are necessary, maintaining the synchronization semantics.


920-926: Consistent diff checking for MAPI spec updates.

The implementation mirrors the CAPI version with appropriate use of HasMetadataChanges(), HasSpecChanges(), and HasProviderSpecChanges() to detect when updates are needed.


947-953: Status update logic correctly adapted.

The function properly integrates with the new DiffResult API, using HasStatusChanges() and the specUpdated flag to gate status updates appropriately.


1021-1024: Platform-aware diff comparison properly integrated.

The call to compareMAPIMachineSets correctly includes the platform parameter to enable platform-specific providerSpec handling, with appropriate error propagation.


1317-1370: Well-structured platform-aware infrastructure template comparison.

The refactored function cleanly handles platform-specific types (AWS, OpenStack, PowerVS) and delegates to the new util.NewDefaultDiffer() for consistent, generalized diffing with proper error handling.


1373-1380: Simplified and consistent CAPI MachineSet comparison.

The refactored function correctly delegates to util.NewDefaultDiffer() for consistent comparison logic, with proper error handling.


1383-1399: Comprehensive platform-aware MAPI MachineSet comparison.

The refactored function properly configures the differ with:

  • Platform-specific providerSpec handling via WithProviderSpec
  • Appropriate status field exclusions (replicas, observedGeneration, etc.) that are managed separately by sync logic
  • Clean error handling and propagation
pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (3)

66-92: LGTM: Clean migration to DiffResult-based spec change detection.

The refactored logic correctly uses diff.HasSpecChanges() to detect when the infrastructure machine needs recreation due to immutable spec changes. The error handling and logging properly capture the diff details for debugging.


124-147: LGTM: Signature update aligns with the new differ approach.

The function signature now accepts util.DiffResult, and the logic correctly uses HasMetadataChanges() for early-exit optimization. This is a clean improvement over the previous map-based approach.


149-204: LGTM: Status update logic correctly uses DiffResult.

The refactored signature and logic properly use diff.HasStatusChanges() to determine when status updates are needed. The generation synchronization check (line 160) ensures consistency between MAPI and CAPI resources.

pkg/controllers/machinesync/machine_sync_controller.go (6)

649-674: LGTM: Spec update logic cleanly migrated to DiffResult.

The refactored function correctly uses capiMachinesDiff.HasMetadataChanges() and capiMachinesDiff.HasSpecChanges() to determine when updates are needed. The early-return optimization on line 653 is logically sound.


697-700: LGTM: Call site properly handles new comparison API.

The error handling and return type match the updated compareCAPIMachines signature, with proper error wrapping.


751-754: LGTM: Platform parameter enables platform-aware diffing.

The addition of the r.Platform parameter is essential for the new platform-aware providerSpec comparison logic. This change aligns with the PR's refactoring objectives.


1254-1261: LGTM: Simplified and type-safe comparison for CAPI machines.

The refactored implementation is clean and concise, delegating to the generalized differ. The error handling properly wraps errors for context. This is a significant improvement over the previous approach.


1264-1279: Excellent: Platform-aware MAPI comparison with providerSpec handling.

This is a key improvement in the refactoring. The differ configuration correctly:

  • Uses platform-specific providerSpec conversion via WithProviderSpec (line 1266)
  • Ignores controller-managed status fields that should not affect sync decisions (lines 1268-1271)
  • Enables deterministic, structured field-by-field comparison

The mapi2capi.ProviderSpecFromRawExtension converter ensures platform-specific providerSpec schemas are handled correctly.


1411-1434: LGTM: MAPI spec update correctly includes providerSpec changes.

The refactored logic properly checks for HasProviderSpecChanges() in addition to metadata and spec changes (line 1415). This is essential for MAPI machines since their providerSpec field contains platform-specific configuration that requires special handling during comparison.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 31, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Summary by CodeRabbit

  • Refactor
  • Consolidated diffing into a unified, platform-aware differ with per-block change checks and improved error propagation; removed legacy map-based diffs.
  • New Features
  • Added a reusable DiffResult interface (metadata/spec/providerSpec/status checks), platform-aware providerSpec handling, and deterministic AWS provider tag ordering.
  • Tests
  • Added unit tests covering diff behaviors, list/nested changes, and condition timestamp handling.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@chrischdi
Copy link
Contributor Author

/retest

@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Nov 14, 2025
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Nov 14, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 14, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

In response to this:

Summary by CodeRabbit

  • Refactor
  • Replaced ad-hoc map diffs with a unified, platform-aware diff API enabling per-block Has* checks, clearer gating of spec/status updates, and consistent error propagation across reconciliation flows.
  • New Features
  • Added a configurable differ with providerSpec extraction, public DiffResult interface, a providerSpec conversion helper, and deterministic ordering for platform-specific data.
  • Tests
  • Added comprehensive unit tests and test suite scaffolding for diff behavior, lists, conditions, and LastTransitionTime handling.
  • Chores
  • Removed legacy map-based comparison helpers and external deep-diff dependency.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@chrischdi
Copy link
Contributor Author

/pipeline required

@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@chrischdi
Copy link
Contributor Author

/retest

2 similar comments
@chrischdi
Copy link
Contributor Author

/retest

@chrischdi
Copy link
Contributor Author

/retest

@chrischdi
Copy link
Contributor Author

Seems like a permafailing job, also for other PRs.

/retest

@chrischdi
Copy link
Contributor Author

/retest

@damdo
Copy link
Member

damdo commented Nov 18, 2025

@chrischdi ci/prow/okd-scos-e2e-aws-ovn job is permafailing don't worry about it :)

@chrischdi chrischdi force-pushed the pr-sync-refactor-how-to-diff branch from 32ead67 to 53d4007 Compare November 18, 2025 13:04
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
pkg/util/diff.go (2)

128-200: Diff pipeline is correct; consider future-proofing modifyFuncs ordering

The overall Diff flow (nil/type checks → unstructured conversion → apply modifyFuncs → apply ignoredPath → per-top-level-key deep.Equal with sorted entries) looks correct and should be deterministic at the result level.

One thing to keep in mind: modifyFuncs is a map, so the order in which modifiers run is unspecified. Today the modifiers (RemoveConditionsLastTransitionTime, ProviderSpec) are independent, so this is fine, but if future options introduce dependencies between modifiers, the order could start to matter. If that ever happens, consider switching modifyFuncs to a slice (or a slice-backed registry) to make the execution order explicit.


275-305: Clarify/confirm semantics when providerSpec is missing

WithProviderSpec currently treats a missing providerSpec (!found) as an error (errProviderSpecNotFound), which will cause Diff to fail rather than just report a diff when one side has a providerSpec and the other does not.

That’s reasonable if all objects passed to a differ configured with WithProviderSpec are expected to always have a providerSpec (and missing it is a programming/config bug). If there are legitimate cases where one or both sides may not have a providerSpec, you might want to instead:

  • treat “both missing” as a no-op, and/or
  • treat “present vs missing” as a regular diff (e.g., by promoting only the present one to providerSpecPath and letting deep.Equal compare nil vs value).

If the “must-exist” assumption is intentional for all current call sites, a short comment on WithProviderSpec to document that contract would help future readers.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3280848 and d2ce231.

📒 Files selected for processing (2)
  • pkg/util/diff.go (1 hunks)
  • pkg/util/diff_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/util/diff_test.go
🔇 Additional comments (1)
pkg/util/diff.go (1)

40-116: DiffResult representation and String() output look solid

The split of Has*Changes by top-level key plus a deterministic String() (sorting and normalizing map[/slice[ prefixes) gives a clear, stable surface for controllers and tests. I don't see correctness issues here, and the behavior matches the examples in the PR discussion.

@damdo
Copy link
Member

damdo commented Nov 19, 2025

/lgtm

Readding to trigger E2Es. Let's see their output

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Nov 19, 2025
@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Nov 21, 2025
@chrischdi
Copy link
Contributor Author

/pipeline required

@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 21, 2025

@chrischdi: This pull request references OCPCLOUD-3172 which is a valid jira issue.

In response to this:

Summary by CodeRabbit

  • Refactor
  • Replaced ad-hoc map diffs with a unified, platform-aware diff result, enabling per-block Has* checks, clearer gating of spec/status updates, and consistent error propagation across reconciliation flows.
  • New Features
  • Added a configurable differ with providerSpec extraction, public DiffResult interface, providerSpec conversion helper, and deterministic ordering for platform-specific data.
  • Tests
  • Added comprehensive unit tests and test-suite scaffolding for diff behavior, lists, conditions, and LastTransitionTime handling.
  • Chores
  • Removed legacy map-based comparison helpers and external deep-diff dependency.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@theobarberbany
Copy link
Contributor

theobarberbany commented Nov 21, 2025

/lgtm

The openshift e2es are painfully flakey. If you've had them green previously, and the only changes are rebase + adding tests (or they're failing on different flakes each time) I'd override them.

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Nov 21, 2025
@openshift-ci-robot
Copy link

Tests from second stage were triggered manually. Pipeline can be controlled only manually, until HEAD changes. Use command to trigger second stage.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Nov 21, 2025

@chrischdi: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/okd-scos-e2e-aws-ovn 3280848 link false /test okd-scos-e2e-aws-ovn
ci/prow/e2e-azure-ovn-techpreview d87410b link false /test e2e-azure-ovn-techpreview
ci/prow/e2e-aws-ovn-serial-1of2 d87410b link true /test e2e-aws-ovn-serial-1of2
ci/prow/e2e-openstack-ovn-techpreview d87410b link true /test e2e-openstack-ovn-techpreview

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants