Skip to content

Commit 14db1d9

Browse files
committed
Improve validation message on build spec update
1 parent e3e4abb commit 14db1d9

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

pkg/build/api/validation/validation.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import (
77
"path/filepath"
88
"strings"
99

10+
"github.com/golang/glog"
11+
1012
kapi "k8s.io/kubernetes/pkg/api"
1113
"k8s.io/kubernetes/pkg/api/validation"
14+
"k8s.io/kubernetes/pkg/runtime"
15+
"k8s.io/kubernetes/pkg/util/strategicpatch"
1216
kvalidation "k8s.io/kubernetes/pkg/util/validation"
1317
"k8s.io/kubernetes/pkg/util/validation/field"
1418

@@ -36,12 +40,43 @@ func ValidateBuildUpdate(build *buildapi.Build, older *buildapi.Build) field.Err
3640
allErrs = append(allErrs, field.Invalid(field.NewPath("status", "phase"), build.Status.Phase, "phase cannot be updated from a terminal state"))
3741
}
3842
if !kapi.Semantic.DeepEqual(build.Spec, older.Spec) {
39-
allErrs = append(allErrs, field.Invalid(field.NewPath("spec"), "content of spec is not printed out, please refer to the \"details\"", "spec is immutable"))
43+
diff, err := diffBuildSpec(build.Spec, older.Spec)
44+
if err != nil {
45+
glog.V(2).Infof("Error calculating build spec patch: %v", err)
46+
diff = "[unknown]"
47+
}
48+
detail := fmt.Sprintf("spec is immutable, diff: %s", diff)
49+
allErrs = append(allErrs, field.Invalid(field.NewPath("spec"), "content of spec is not printed out, please refer to the details", detail))
4050
}
4151

4252
return allErrs
4353
}
4454

55+
func diffBuildSpec(newer buildapi.BuildSpec, older buildapi.BuildSpec) (string, error) {
56+
version := buildapi.SchemeGroupVersion
57+
codec := kapi.Codecs.LegacyCodec(version)
58+
newerObj := &buildapi.Build{Spec: newer}
59+
olderObj := &buildapi.Build{Spec: older}
60+
61+
newerJSON, err := runtime.Encode(codec, newerObj)
62+
if err != nil {
63+
return "", fmt.Errorf("error encoding newer: %v", err)
64+
}
65+
olderJSON, err := runtime.Encode(codec, olderObj)
66+
if err != nil {
67+
return "", fmt.Errorf("error encoding older: %v", err)
68+
}
69+
versioned, err := kapi.Scheme.ConvertToVersion(newerObj, version.String())
70+
if err != nil {
71+
return "", fmt.Errorf("error converting newer to versioned: %v", err)
72+
}
73+
patch, err := strategicpatch.CreateTwoWayMergePatch(olderJSON, newerJSON, versioned)
74+
if err != nil {
75+
return "", fmt.Errorf("error creating a strategic patch: %v", err)
76+
}
77+
return string(patch), nil
78+
}
79+
4580
// refKey returns a key for the given ObjectReference. If the ObjectReference
4681
// doesn't include a namespace, the passed in namespace is used for the reference
4782
func refKey(namespace string, ref *kapi.ObjectReference) string {

pkg/build/api/validation/validation_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"k8s.io/kubernetes/pkg/util/validation/field"
1010

1111
buildapi "github.com/openshift/origin/pkg/build/api"
12+
13+
_ "github.com/openshift/origin/pkg/build/api/install"
1214
)
1315

1416
func TestBuildValidationSuccess(t *testing.T) {
@@ -2320,3 +2322,79 @@ func TestValidatePostCommit(t *testing.T) {
23202322
}
23212323
}
23222324
}
2325+
2326+
func TestDiffBuildSpec(t *testing.T) {
2327+
tests := []struct {
2328+
name string
2329+
older, newer buildapi.BuildSpec
2330+
expected string
2331+
}{
2332+
{
2333+
older: buildapi.BuildSpec{
2334+
CommonSpec: buildapi.CommonSpec{
2335+
Source: buildapi.BuildSource{},
2336+
},
2337+
},
2338+
newer: buildapi.BuildSpec{
2339+
CommonSpec: buildapi.CommonSpec{
2340+
Source: buildapi.BuildSource{
2341+
ContextDir: "context-dir",
2342+
},
2343+
},
2344+
},
2345+
expected: `{"Spec":{"Source":{"ContextDir":"context-dir"}}}`,
2346+
},
2347+
{
2348+
older: buildapi.BuildSpec{
2349+
CommonSpec: buildapi.CommonSpec{
2350+
Source: buildapi.BuildSource{
2351+
Git: &buildapi.GitBuildSource{
2352+
Ref: "https://github.com/openshift/origin.git",
2353+
},
2354+
},
2355+
},
2356+
},
2357+
newer: buildapi.BuildSpec{
2358+
CommonSpec: buildapi.CommonSpec{
2359+
Source: buildapi.BuildSource{
2360+
Git: &buildapi.GitBuildSource{
2361+
Ref: "https://github.com/openshift/origin.git",
2362+
},
2363+
},
2364+
},
2365+
},
2366+
expected: "{}",
2367+
},
2368+
{
2369+
older: buildapi.BuildSpec{
2370+
CommonSpec: buildapi.CommonSpec{
2371+
Source: buildapi.BuildSource{
2372+
Git: &buildapi.GitBuildSource{
2373+
Ref: "https://github.com/openshift/origin.git",
2374+
},
2375+
},
2376+
},
2377+
},
2378+
newer: buildapi.BuildSpec{
2379+
CommonSpec: buildapi.CommonSpec{
2380+
Source: buildapi.BuildSource{
2381+
Git: &buildapi.GitBuildSource{
2382+
Ref: "https://github.com/ose/origin.git",
2383+
},
2384+
},
2385+
},
2386+
},
2387+
expected: `{"Spec":{"Source":{"Git":{"Ref":"https://github.com/ose/origin.git"}}}}`,
2388+
},
2389+
}
2390+
for _, test := range tests {
2391+
diff, err := diffBuildSpec(test.newer, test.older)
2392+
if err != nil {
2393+
t.Errorf("%s: unexpected: %v", test.name, err)
2394+
continue
2395+
}
2396+
if diff != test.expected {
2397+
t.Errorf("%s: expected: %s, got: %s", test.name, test.expected, diff)
2398+
}
2399+
}
2400+
}

0 commit comments

Comments
 (0)