Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix: detect manual changes on CRDs and CRs with three-way-merge #923

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
yxxhero wants to merge 9 commits into master
base: master
Choose a base branch
Loading
from fix/cr-three-way-merge
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit Hold shift + click to select a range
115630c
fix: detect manual changes on CRDs and CRs with three-way-merge
yxxhero Feb 1, 2026
6610be9
test: add tests for three-way merge with unstructured objects
yxxhero Feb 1, 2026
a460e71
fix: properly detect drift when chart unchanged for unstructured objects
yxxhero Feb 1, 2026
efb7e0a
fix: correct comment direction in three-way merge logic
yxxhero Feb 1, 2026
a59ce03
fix: clean metadata fields to avoid resourceVersion patch errors
yxxhero Feb 14, 2026
5d14d97
fix: preserve live-only fields in three-way merge for unstructured ob...
yxxhero Feb 14, 2026
f5b13c2
refactor: reuse deleteStatusAndTidyMetadata in cleanMetadataForPatch
yxxhero Feb 14, 2026
2ff4b31
fix: handle null input in deleteStatusAndTidyMetadata
yxxhero Feb 15, 2026
1076d7d
fix: improve error handling and type safety
yxxhero Feb 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: reuse deleteStatusAndTidyMetadata in cleanMetadataForPatch
- Refactor cleanMetadataForPatch to call deleteStatusAndTidyMetadata
 to avoid code duplication and ensure consistent metadata handling
- Add TestCreatePatchForCRD test case to cover the CRD type branch
 (apiextv1.CustomResourceDefinition path)
Signed-off-by: yxxhero <aiopsclub@163.com>
  • Loading branch information
yxxhero committed Feb 14, 2026
commit f5b13c210517e9f509751569767ecc50549b5048

Some comments aren't visible on the classic Files Changed page.

27 changes: 2 additions & 25 deletions manifest/generate.go
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -244,33 +244,10 @@ func isPatchEmpty(patch []byte) bool {
}

func cleanMetadataForPatch(data []byte) ([]byte, error) {
var objMap map[string]interface{}
if err := json.Unmarshal(data, &objMap); err != nil {
objMap, err := deleteStatusAndTidyMetadata(data)
if err != nil {
return nil, err
}

delete(objMap, "status")

if metadata, ok := objMap["metadata"].(map[string]interface{}); ok {
delete(metadata, "managedFields")
delete(metadata, "generation")
delete(metadata, "creationTimestamp")
delete(metadata, "resourceVersion")
delete(metadata, "uid")

// Remove helm-related and k8s annotations that shouldn't be compared
if a := metadata["annotations"]; a != nil {
annotations := a.(map[string]interface{})
delete(annotations, "meta.helm.sh/release-name")
delete(annotations, "meta.helm.sh/release-namespace")
delete(annotations, "deployment.kubernetes.io/revision")

if len(annotations) == 0 {
delete(metadata, "annotations")
}
}
}

return json.Marshal(objMap)
}
Comment on lines +252 to +261

Copilot AI Feb 14, 2026

Copy link

Choose a reason for hiding this comment

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

cleanMetadataForPatch largely overlaps with deleteStatusAndTidyMetadata (manifest/util.go) but removes a different set of metadata fields/annotations (e.g., meta.helm.sh/* and deployment.kubernetes.io/revision are handled in the other helper but not here). Having two slightly different "tidy metadata" implementations risks inconsistent behavior between patch generation and manifest rendering. Suggest reusing/extracting the existing helper (or at least aligning the exact fields removed) so the same metadata is ignored everywhere.

Copilot uses AI. Check for mistakes.

Expand Down
100 changes: 100 additions & 0 deletions manifest/generate_test.go
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"testing"

"github.com/stretchr/testify/require"
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -318,3 +320,101 @@ func TestCreatePatchForUnstructured(t *testing.T) {
})
}
}

// TestCreatePatchForCRD tests the three-way merge implementation for CRD objects.
// This ensures the isCRD branch in createPatch is properly covered.
func TestCreatePatchForCRD(t *testing.T) {
originalCRD := &apiextv1.CustomResourceDefinition{
TypeMeta: metav1.TypeMeta{
APIVersion: "apiextensions.k8s.io/v1",
Kind: "CustomResourceDefinition",
},
ObjectMeta: metav1.ObjectMeta{
Name: "crds.example.com",
},
Spec: apiextv1.CustomResourceDefinitionSpec{
Group: "example.com",
Names: apiextv1.CustomResourceDefinitionNames{
Plural: "crds",
Singular: "crd",
Kind: "Crd",
},
Versions: []apiextv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
},
},
},
}

currentCRD := &apiextv1.CustomResourceDefinition{
TypeMeta: metav1.TypeMeta{
APIVersion: "apiextensions.k8s.io/v1",
Kind: "CustomResourceDefinition",
},
ObjectMeta: metav1.ObjectMeta{
Name: "crds.example.com",
},
Spec: apiextv1.CustomResourceDefinitionSpec{
Group: "example.com",
Names: apiextv1.CustomResourceDefinitionNames{
Plural: "crds",
Singular: "crd",
Kind: "Crd",
},
Versions: []apiextv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
},
},
},
}

targetCRD := &apiextv1.CustomResourceDefinition{
TypeMeta: metav1.TypeMeta{
APIVersion: "apiextensions.k8s.io/v1",
Kind: "CustomResourceDefinition",
},
ObjectMeta: metav1.ObjectMeta{
Name: "crds.example.com",
},
Spec: apiextv1.CustomResourceDefinitionSpec{
Group: "example.com",
Names: apiextv1.CustomResourceDefinitionNames{
Plural: "crds",
Singular: "crd",
Kind: "Crd",
},
Versions: []apiextv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
},
},
},
}

target := &resource.Info{
Mapping: &meta.RESTMapping{
GroupVersionKind: schema.GroupVersionKind{
Group: "apiextensions.k8s.io",
Version: "v1",
Kind: "CustomResourceDefinition",
},
},
Object: targetCRD,
}

patch, patchType, err := createPatch(originalCRD, currentCRD, target)
require.NoError(t, err, "createPatch should not return an error for CRD")
require.Equal(t, types.MergePatchType, patchType, "patch type should be MergePatchType for CRD objects")

t.Logf("CRD Patch result: %s", string(patch))

require.Equal(t, "{}", string(patch), "CRD with no changes should result in empty patch")
}
Loading

AltStyle によって変換されたページ (->オリジナル) /