| ... | ... |
@@ -142,7 +142,7 @@ func validateCommonSpec(spec *buildapi.CommonSpec, fldPath *field.Path) field.Er |
| 142 | 142 |
s := spec.Strategy |
| 143 | 143 |
|
| 144 | 144 |
if s.DockerStrategy != nil && s.JenkinsPipelineStrategy == nil && spec.Source.Git == nil && spec.Source.Binary == nil && spec.Source.Dockerfile == nil && spec.Source.Images == nil {
|
| 145 |
- allErrs = append(allErrs, field.Invalid(fldPath.Child("source"), spec.Source, "must provide a value for at least one of source, binary, images, or dockerfile"))
|
|
| 145 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("source"), "", "must provide a value for at least one source input(git, binary, dockerfile, images)."))
|
|
| 146 | 146 |
} |
| 147 | 147 |
|
| 148 | 148 |
allErrs = append(allErrs, |
| ... | ... |
@@ -202,7 +202,6 @@ func validateSource(input *buildapi.BuildSource, isCustomStrategy, isDockerStrat |
| 202 | 202 |
allErrs = append(allErrs, validateImageSource(image, fldPath.Child("images").Index(i))...)
|
| 203 | 203 |
} |
| 204 | 204 |
} |
| 205 |
- |
|
| 206 | 205 |
if isJenkinsPipelineStrategyFromRepo && input.Git == nil {
|
| 207 | 206 |
allErrs = append(allErrs, field.Invalid(fldPath.Child("git"), "", "must be set when using Jenkins Pipeline strategy with Jenkinsfile from a git repo"))
|
| 208 | 207 |
} |
| ... | ... |
@@ -46,7 +46,7 @@ func TestBuildValidationSuccess(t *testing.T) {
|
| 46 | 46 |
|
| 47 | 47 |
func checkDockerStrategyEmptySourceError(result field.ErrorList) bool {
|
| 48 | 48 |
for _, err := range result {
|
| 49 |
- if err.Type == field.ErrorTypeInvalid && strings.Contains(err.Field, "spec.source") && strings.Contains(err.Detail, "must provide a value for at least one of source, binary, images, or dockerfile") {
|
|
| 49 |
+ if err.Type == field.ErrorTypeInvalid && strings.Contains(err.Field, "spec.source") && strings.Contains(err.Detail, "must provide a value for at least one source input(git, binary, dockerfile, images).") {
|
|
| 50 | 50 |
return true |
| 51 | 51 |
} |
| 52 | 52 |
} |
| ... | ... |
@@ -1632,7 +1632,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1632 | 1632 |
}, |
| 1633 | 1633 |
}, |
| 1634 | 1634 |
}, |
| 1635 |
- // 17 |
|
| 1635 |
+ // 18 |
|
| 1636 | 1636 |
// dockerfilePath can't equal .. |
| 1637 | 1637 |
{
|
| 1638 | 1638 |
string(field.ErrorTypeInvalid) + "strategy.dockerStrategy.dockerfilePath", |
| ... | ... |
@@ -1656,7 +1656,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1656 | 1656 |
}, |
| 1657 | 1657 |
}, |
| 1658 | 1658 |
}, |
| 1659 |
- // 18 |
|
| 1659 |
+ // 19 |
|
| 1660 | 1660 |
{
|
| 1661 | 1661 |
string(field.ErrorTypeInvalid) + "postCommit", |
| 1662 | 1662 |
buildapi.CommonSpec{
|
| ... | ... |
@@ -1674,7 +1674,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1674 | 1674 |
}, |
| 1675 | 1675 |
}, |
| 1676 | 1676 |
}, |
| 1677 |
- // 19 |
|
| 1677 |
+ // 20 |
|
| 1678 | 1678 |
{
|
| 1679 | 1679 |
string(field.ErrorTypeInvalid) + "source.git", |
| 1680 | 1680 |
buildapi.CommonSpec{
|
| ... | ... |
@@ -1683,7 +1683,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1683 | 1683 |
}, |
| 1684 | 1684 |
}, |
| 1685 | 1685 |
}, |
| 1686 |
- // 20 |
|
| 1686 |
+ // 21 |
|
| 1687 | 1687 |
{
|
| 1688 | 1688 |
string(field.ErrorTypeInvalid) + "source.git", |
| 1689 | 1689 |
buildapi.CommonSpec{
|
| ... | ... |
@@ -1694,7 +1694,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1694 | 1694 |
}, |
| 1695 | 1695 |
}, |
| 1696 | 1696 |
}, |
| 1697 |
- // 21 |
|
| 1697 |
+ // 22 |
|
| 1698 | 1698 |
// jenkinsfilePath can't be an absolute path |
| 1699 | 1699 |
{
|
| 1700 | 1700 |
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfilePath", |
| ... | ... |
@@ -1711,7 +1711,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1711 | 1711 |
}, |
| 1712 | 1712 |
}, |
| 1713 | 1713 |
}, |
| 1714 |
- // 22 |
|
| 1714 |
+ // 23 |
|
| 1715 | 1715 |
// jenkinsfilePath can't start with ../ |
| 1716 | 1716 |
{
|
| 1717 | 1717 |
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfilePath", |
| ... | ... |
@@ -1728,7 +1728,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1728 | 1728 |
}, |
| 1729 | 1729 |
}, |
| 1730 | 1730 |
}, |
| 1731 |
- // 23 |
|
| 1731 |
+ // 24 |
|
| 1732 | 1732 |
// jenkinsfilePath can't be a reference a path outside of the dir |
| 1733 | 1733 |
{
|
| 1734 | 1734 |
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfilePath", |
| ... | ... |
@@ -1745,7 +1745,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1745 | 1745 |
}, |
| 1746 | 1746 |
}, |
| 1747 | 1747 |
}, |
| 1748 |
- // 24 |
|
| 1748 |
+ // 25 |
|
| 1749 | 1749 |
// jenkinsfilePath can't be equal to .. |
| 1750 | 1750 |
{
|
| 1751 | 1751 |
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfilePath", |
| ... | ... |
@@ -1762,7 +1762,7 @@ func TestValidateCommonSpec(t *testing.T) {
|
| 1762 | 1762 |
}, |
| 1763 | 1763 |
}, |
| 1764 | 1764 |
}, |
| 1765 |
- // 25 |
|
| 1765 |
+ // 26 |
|
| 1766 | 1766 |
// path must be shorter than 100k |
| 1767 | 1767 |
{
|
| 1768 | 1768 |
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfile", |
| ... | ... |
@@ -302,12 +302,16 @@ func (m *mockBuildConfigUpdater) Update(buildcfg *buildapi.BuildConfig) error {
|
| 302 | 302 |
} |
| 303 | 303 |
|
| 304 | 304 |
func mockBuildConfig(baseImage, triggerImage, repoName, repoTag string) *buildapi.BuildConfig {
|
| 305 |
+ dockerfile := "FROM foo" |
|
| 305 | 306 |
return &buildapi.BuildConfig{
|
| 306 | 307 |
ObjectMeta: kapi.ObjectMeta{
|
| 307 | 308 |
Name: "testBuildCfg", |
| 308 | 309 |
}, |
| 309 | 310 |
Spec: buildapi.BuildConfigSpec{
|
| 310 | 311 |
CommonSpec: buildapi.CommonSpec{
|
| 312 |
+ Source: buildapi.BuildSource{
|
|
| 313 |
+ Dockerfile: &dockerfile, |
|
| 314 |
+ }, |
|
| 311 | 315 |
Strategy: buildapi.BuildStrategy{
|
| 312 | 316 |
DockerStrategy: &buildapi.DockerBuildStrategy{
|
| 313 | 317 |
From: &kapi.ObjectReference{
|
| ... | ... |
@@ -218,9 +218,8 @@ func (g *BuildGenerator) Instantiate(ctx kapi.Context, request *buildapi.BuildRe |
| 218 | 218 |
if err != nil {
|
| 219 | 219 |
return nil, err |
| 220 | 220 |
} |
| 221 |
- |
|
| 222 | 221 |
if buildutil.IsPaused(bc) {
|
| 223 |
- return nil, errors.NewInternalError(&GeneratorFatalError{fmt.Sprintf("can't instantiate from BuildConfig %s/%s: BuildConfig is paused", bc.Namespace, bc.Name)})
|
|
| 222 |
+ return nil, errors.NewBadRequest(fmt.Sprintf("can't instantiate from BuildConfig %s/%s: BuildConfig is paused", bc.Namespace, bc.Name))
|
|
| 224 | 223 |
} |
| 225 | 224 |
|
| 226 | 225 |
if err := g.checkLastVersion(bc, request.LastVersion); err != nil {
|
| ... | ... |
@@ -333,7 +332,6 @@ func (g *BuildGenerator) Clone(ctx kapi.Context, request *buildapi.BuildRequest) |
| 333 | 333 |
if err != nil && !errors.IsNotFound(err) {
|
| 334 | 334 |
return nil, err |
| 335 | 335 |
} |
| 336 |
- |
|
| 337 | 336 |
if buildutil.IsPaused(buildConfig) {
|
| 338 | 337 |
return nil, errors.NewInternalError(&GeneratorFatalError{fmt.Sprintf("can't instantiate from BuildConfig %s/%s: BuildConfig is paused", buildConfig.Namespace, buildConfig.Name)})
|
| 339 | 338 |
} |
| ... | ... |
@@ -366,7 +364,6 @@ func (g *BuildGenerator) createBuild(ctx kapi.Context, build *buildapi.Build) (* |
| 366 | 366 |
return nil, errors.NewConflict(buildapi.Resource("build"), build.Namespace, fmt.Errorf("Build.Namespace does not match the provided context"))
|
| 367 | 367 |
} |
| 368 | 368 |
kapi.FillObjectMetaSystemFields(ctx, &build.ObjectMeta) |
| 369 |
- |
|
| 370 | 369 |
err := g.Client.CreateBuild(ctx, build) |
| 371 | 370 |
if err != nil {
|
| 372 | 371 |
return nil, err |
| ... | ... |
@@ -416,13 +413,15 @@ func (g *BuildGenerator) generateBuildFromConfig(ctx kapi.Context, bc *buildapi. |
| 416 | 416 |
}, |
| 417 | 417 |
}, |
| 418 | 418 |
} |
| 419 |
- |
|
| 420 | 419 |
if binary != nil {
|
| 421 | 420 |
build.Spec.Source.Git = nil |
| 422 | 421 |
build.Spec.Source.Binary = binary |
| 423 | 422 |
if build.Spec.Source.Dockerfile != nil && binary.AsFile == "Dockerfile" {
|
| 424 | 423 |
build.Spec.Source.Dockerfile = nil |
| 425 | 424 |
} |
| 425 |
+ } else {
|
|
| 426 |
+ // must explicitly set this because we copied the source values from the buildconfig. |
|
| 427 |
+ build.Spec.Source.Binary = nil |
|
| 426 | 428 |
} |
| 427 | 429 |
|
| 428 | 430 |
build.Name = getNextBuildName(bc) |
| ... | ... |
@@ -698,6 +697,8 @@ func generateBuildFromBuild(build *buildapi.Build, buildConfig *buildapi.BuildCo |
| 698 | 698 |
Config: buildCopy.Status.Config, |
| 699 | 699 |
}, |
| 700 | 700 |
} |
| 701 |
+ // TODO remove/update this when we support cloning binary builds |
|
| 702 |
+ newBuild.Spec.Source.Binary = nil |
|
| 701 | 703 |
if newBuild.Annotations == nil {
|
| 702 | 704 |
newBuild.Annotations = make(map[string]string) |
| 703 | 705 |
} |
| ... | ... |
@@ -48,6 +48,25 @@ func TestInstantiate(t *testing.T) {
|
| 48 | 48 |
} |
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 |
+func TestInstantiateBinary(t *testing.T) {
|
|
| 52 |
+ generator := mockBuildGenerator() |
|
| 53 |
+ build, err := generator.Instantiate(kapi.NewDefaultContext(), &buildapi.BuildRequest{Binary: &buildapi.BinaryBuildSource{}})
|
|
| 54 |
+ if err != nil {
|
|
| 55 |
+ t.Errorf("Unexpected error %v", err)
|
|
| 56 |
+ } |
|
| 57 |
+ if build.Spec.Source.Binary == nil {
|
|
| 58 |
+ t.Errorf("build should have a binary source value, has nil")
|
|
| 59 |
+ } |
|
| 60 |
+ build, err = generator.Clone(kapi.NewDefaultContext(), &buildapi.BuildRequest{Binary: &buildapi.BinaryBuildSource{}})
|
|
| 61 |
+ if err != nil {
|
|
| 62 |
+ t.Errorf("Unexpected error %v", err)
|
|
| 63 |
+ } |
|
| 64 |
+ // TODO: we should enable this flow. |
|
| 65 |
+ if build.Spec.Source.Binary != nil {
|
|
| 66 |
+ t.Errorf("build should not have a binary source value, has %v", build.Spec.Source.Binary)
|
|
| 67 |
+ } |
|
| 68 |
+} |
|
| 69 |
+ |
|
| 51 | 70 |
// TODO(agoldste): I'm not sure the intent of this test. Using the previous logic for |
| 52 | 71 |
// the generator, which would try to update the build config before creating |
| 53 | 72 |
// the build, I can see why the UpdateBuildConfigFunc is set up to return an |
| ... | ... |
@@ -83,6 +102,7 @@ func TestInstantiateRetry(t *testing.T) {
|
| 83 | 83 |
*/ |
| 84 | 84 |
|
| 85 | 85 |
func TestInstantiateDeletingError(t *testing.T) {
|
| 86 |
+ source := mocks.MockSource() |
|
| 86 | 87 |
generator := BuildGenerator{Client: Client{
|
| 87 | 88 |
GetBuildConfigFunc: func(ctx kapi.Context, name string) (*buildapi.BuildConfig, error) {
|
| 88 | 89 |
bc := &buildapi.BuildConfig{
|
| ... | ... |
@@ -91,11 +111,31 @@ func TestInstantiateDeletingError(t *testing.T) {
|
| 91 | 91 |
buildapi.BuildConfigPausedAnnotation: "true", |
| 92 | 92 |
}, |
| 93 | 93 |
}, |
| 94 |
+ Spec: buildapi.BuildConfigSpec{
|
|
| 95 |
+ CommonSpec: buildapi.CommonSpec{
|
|
| 96 |
+ Source: source, |
|
| 97 |
+ Revision: &buildapi.SourceRevision{
|
|
| 98 |
+ Git: &buildapi.GitSourceRevision{
|
|
| 99 |
+ Commit: "1234", |
|
| 100 |
+ }, |
|
| 101 |
+ }, |
|
| 102 |
+ }, |
|
| 103 |
+ }, |
|
| 94 | 104 |
} |
| 95 | 105 |
return bc, nil |
| 96 | 106 |
}, |
| 97 | 107 |
GetBuildFunc: func(ctx kapi.Context, name string) (*buildapi.Build, error) {
|
| 98 | 108 |
build := &buildapi.Build{
|
| 109 |
+ Spec: buildapi.BuildSpec{
|
|
| 110 |
+ CommonSpec: buildapi.CommonSpec{
|
|
| 111 |
+ Source: source, |
|
| 112 |
+ Revision: &buildapi.SourceRevision{
|
|
| 113 |
+ Git: &buildapi.GitSourceRevision{
|
|
| 114 |
+ Commit: "1234", |
|
| 115 |
+ }, |
|
| 116 |
+ }, |
|
| 117 |
+ }, |
|
| 118 |
+ }, |
|
| 99 | 119 |
Status: buildapi.BuildStatus{
|
| 100 | 120 |
Config: &kapi.ObjectReference{
|
| 101 | 121 |
Name: "buildconfig", |
| ... | ... |
@@ -115,6 +155,61 @@ func TestInstantiateDeletingError(t *testing.T) {
|
| 115 | 115 |
} |
| 116 | 116 |
} |
| 117 | 117 |
|
| 118 |
+// TestInstantiateBinaryClear ensures that when instantiating or cloning from a buildconfig/build |
|
| 119 |
+// that has a binary source value, the resulting build does not have a binary source value |
|
| 120 |
+// (because the request did not include one) |
|
| 121 |
+func TestInstantiateBinaryRemoved(t *testing.T) {
|
|
| 122 |
+ generator := mockBuildGenerator() |
|
| 123 |
+ client := generator.Client.(Client) |
|
| 124 |
+ client.GetBuildConfigFunc = func(ctx kapi.Context, name string) (*buildapi.BuildConfig, error) {
|
|
| 125 |
+ bc := &buildapi.BuildConfig{
|
|
| 126 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 127 |
+ Annotations: map[string]string{},
|
|
| 128 |
+ }, |
|
| 129 |
+ Spec: buildapi.BuildConfigSpec{
|
|
| 130 |
+ CommonSpec: buildapi.CommonSpec{
|
|
| 131 |
+ Source: buildapi.BuildSource{
|
|
| 132 |
+ Binary: &buildapi.BinaryBuildSource{},
|
|
| 133 |
+ }, |
|
| 134 |
+ }, |
|
| 135 |
+ }, |
|
| 136 |
+ } |
|
| 137 |
+ return bc, nil |
|
| 138 |
+ } |
|
| 139 |
+ client.GetBuildFunc = func(ctx kapi.Context, name string) (*buildapi.Build, error) {
|
|
| 140 |
+ build := &buildapi.Build{
|
|
| 141 |
+ Spec: buildapi.BuildSpec{
|
|
| 142 |
+ CommonSpec: buildapi.CommonSpec{
|
|
| 143 |
+ Source: buildapi.BuildSource{
|
|
| 144 |
+ Binary: &buildapi.BinaryBuildSource{},
|
|
| 145 |
+ }, |
|
| 146 |
+ }, |
|
| 147 |
+ }, |
|
| 148 |
+ Status: buildapi.BuildStatus{
|
|
| 149 |
+ Config: &kapi.ObjectReference{
|
|
| 150 |
+ Name: "buildconfig", |
|
| 151 |
+ }, |
|
| 152 |
+ }, |
|
| 153 |
+ } |
|
| 154 |
+ return build, nil |
|
| 155 |
+ } |
|
| 156 |
+ |
|
| 157 |
+ build, err := generator.Instantiate(kapi.NewDefaultContext(), &buildapi.BuildRequest{})
|
|
| 158 |
+ if err != nil {
|
|
| 159 |
+ t.Errorf("Unexpected error %v", err)
|
|
| 160 |
+ } |
|
| 161 |
+ if build.Spec.Source.Binary != nil {
|
|
| 162 |
+ t.Errorf("build should not have a binary source value, has %v", build.Spec.Source.Binary)
|
|
| 163 |
+ } |
|
| 164 |
+ build, err = generator.Clone(kapi.NewDefaultContext(), &buildapi.BuildRequest{})
|
|
| 165 |
+ if err != nil {
|
|
| 166 |
+ t.Errorf("Unexpected error %v", err)
|
|
| 167 |
+ } |
|
| 168 |
+ if build.Spec.Source.Binary != nil {
|
|
| 169 |
+ t.Errorf("build should not have a binary source value, has %v", build.Spec.Source.Binary)
|
|
| 170 |
+ } |
|
| 171 |
+} |
|
| 172 |
+ |
|
| 118 | 173 |
func TestInstantiateGetBuildConfigError(t *testing.T) {
|
| 119 | 174 |
generator := BuildGenerator{Client: Client{
|
| 120 | 175 |
GetBuildConfigFunc: func(ctx kapi.Context, name string) (*buildapi.BuildConfig, error) {
|
| ... | ... |
@@ -240,6 +335,7 @@ func TestInstantiateWithImageTrigger(t *testing.T) {
|
| 240 | 240 |
}, |
| 241 | 241 |
} |
| 242 | 242 |
|
| 243 |
+ source := mocks.MockSource() |
|
| 243 | 244 |
for _, tc := range tests {
|
| 244 | 245 |
bc := &buildapi.BuildConfig{
|
| 245 | 246 |
Spec: buildapi.BuildConfigSpec{
|
| ... | ... |
@@ -252,6 +348,12 @@ func TestInstantiateWithImageTrigger(t *testing.T) {
|
| 252 | 252 |
}, |
| 253 | 253 |
}, |
| 254 | 254 |
}, |
| 255 |
+ Source: source, |
|
| 256 |
+ Revision: &buildapi.SourceRevision{
|
|
| 257 |
+ Git: &buildapi.GitSourceRevision{
|
|
| 258 |
+ Commit: "1234", |
|
| 259 |
+ }, |
|
| 260 |
+ }, |
|
| 255 | 261 |
}, |
| 256 | 262 |
Triggers: tc.triggers, |
| 257 | 263 |
}, |
| ... | ... |
@@ -19,6 +19,7 @@ import ( |
| 19 | 19 |
"github.com/spf13/cobra" |
| 20 | 20 |
|
| 21 | 21 |
kapi "k8s.io/kubernetes/pkg/api" |
| 22 |
+ kerrors "k8s.io/kubernetes/pkg/api/errors" |
|
| 22 | 23 |
"k8s.io/kubernetes/pkg/api/unversioned" |
| 23 | 24 |
"k8s.io/kubernetes/pkg/client/restclient" |
| 24 | 25 |
kclientcmd "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" |
| ... | ... |
@@ -30,7 +31,7 @@ import ( |
| 30 | 30 |
cmdutil "github.com/openshift/origin/pkg/cmd/util" |
| 31 | 31 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
| 32 | 32 |
"github.com/openshift/origin/pkg/generate/git" |
| 33 |
- "github.com/openshift/origin/pkg/util/errors" |
|
| 33 |
+ oerrors "github.com/openshift/origin/pkg/util/errors" |
|
| 34 | 34 |
"github.com/openshift/source-to-image/pkg/tar" |
| 35 | 35 |
) |
| 36 | 36 |
|
| ... | ... |
@@ -165,6 +166,11 @@ func (o *StartBuildOptions) Complete(f *clientcmd.Factory, in io.Reader, out io. |
| 165 | 165 |
return kcmdutil.UsageError(cmd, "Must pass a name of a build config or specify build name with '--from-build' flag") |
| 166 | 166 |
} |
| 167 | 167 |
|
| 168 |
+ if len(buildName) != 0 && (len(fromFile) != 0 || len(fromDir) != 0 || len(fromRepo) != 0) {
|
|
| 169 |
+ // TODO: we should support this, it should be possible to clone a build to run again with new uploaded artifacts. |
|
| 170 |
+ // Doing so requires introducing a new clonebinary endpoint. |
|
| 171 |
+ return kcmdutil.UsageError(cmd, "Cannot use '--from-build' flag with binary builds") |
|
| 172 |
+ } |
|
| 168 | 173 |
o.AsBinary = len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0 |
| 169 | 174 |
|
| 170 | 175 |
namespace, _, err := f.DefaultNamespace() |
| ... | ... |
@@ -282,10 +288,16 @@ func (o *StartBuildOptions) Run() error {
|
| 282 | 282 |
} |
| 283 | 283 |
case len(o.FromBuild) > 0: |
| 284 | 284 |
if newBuild, err = o.Client.Builds(o.Namespace).Clone(request); err != nil {
|
| 285 |
+ if isInvalidSourceInputsError(err) {
|
|
| 286 |
+ return fmt.Errorf("Build %s/%s has no valid source inputs and '--from-build' cannot be used for binary builds", o.Namespace, o.Name)
|
|
| 287 |
+ } |
|
| 285 | 288 |
return err |
| 286 | 289 |
} |
| 287 | 290 |
default: |
| 288 | 291 |
if newBuild, err = o.Client.BuildConfigs(o.Namespace).Instantiate(request); err != nil {
|
| 292 |
+ if isInvalidSourceInputsError(err) {
|
|
| 293 |
+ return fmt.Errorf("Build configuration %s/%s has no valid source inputs, if this is a binary build you must specify one of '--from-dir', '--from-repo', or '--from-file'", o.Namespace, o.Name)
|
|
| 294 |
+ } |
|
| 289 | 295 |
return err |
| 290 | 296 |
} |
| 291 | 297 |
} |
| ... | ... |
@@ -327,7 +339,7 @@ func (o *StartBuildOptions) Run() error {
|
| 327 | 327 |
if err != nil {
|
| 328 | 328 |
// if --wait options is set, then retry the connection to build logs |
| 329 | 329 |
// when we hit the timeout. |
| 330 |
- if o.WaitForComplete && errors.IsTimeoutErr(err) {
|
|
| 330 |
+ if o.WaitForComplete && oerrors.IsTimeoutErr(err) {
|
|
| 331 | 331 |
continue |
| 332 | 332 |
} |
| 333 | 333 |
fmt.Fprintf(o.ErrOut, "error getting logs: %v\n", err) |
| ... | ... |
@@ -717,3 +729,18 @@ func WaitForBuildComplete(c osclient.BuildInterface, name string) error {
|
| 717 | 717 |
} |
| 718 | 718 |
} |
| 719 | 719 |
} |
| 720 |
+ |
|
| 721 |
+func isInvalidSourceInputsError(err error) bool {
|
|
| 722 |
+ if err != nil {
|
|
| 723 |
+ if statusErr, ok := err.(*kerrors.StatusError); ok {
|
|
| 724 |
+ if kerrors.IsInvalid(statusErr) {
|
|
| 725 |
+ for _, cause := range statusErr.ErrStatus.Details.Causes {
|
|
| 726 |
+ if cause.Field == "spec.source" {
|
|
| 727 |
+ return true |
|
| 728 |
+ } |
|
| 729 |
+ } |
|
| 730 |
+ } |
|
| 731 |
+ } |
|
| 732 |
+ } |
|
| 733 |
+ return false |
|
| 734 |
+} |
| ... | ... |
@@ -163,6 +163,9 @@ started=$(oc start-build ruby-sample-build-invalidtag) |
| 163 | 163 |
os::cmd::expect_success_and_text "oc describe build ${started}" 'centos/ruby-22-centos7$'
|
| 164 | 164 |
frombuild=$(oc start-build --from-build="${started}")
|
| 165 | 165 |
os::cmd::expect_success_and_text "oc describe build ${frombuild}" 'centos/ruby-22-centos7$'
|
| 166 |
+os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-dir=. --from-build=${started}" "Cannot use '--from-build' flag with binary builds"
|
|
| 167 |
+os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-file=. --from-build=${started}" "Cannot use '--from-build' flag with binary builds"
|
|
| 168 |
+os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-repo=. --from-build=${started}" "Cannot use '--from-build' flag with binary builds"
|
|
| 166 | 169 |
echo "start-build: ok" |
| 167 | 170 |
os::test::junit::declare_suite_end |
| 168 | 171 |
|
| ... | ... |
@@ -155,6 +155,34 @@ var _ = g.Describe("[builds][Slow] starting a build using CLI", func() {
|
| 155 | 155 |
} |
| 156 | 156 |
o.Expect(err).NotTo(o.HaveOccurred()) |
| 157 | 157 |
}) |
| 158 |
+ |
|
| 159 |
+ // run one valid binary build so we can do --from-build later |
|
| 160 |
+ g.It("should reject binary build requests without a --from-xxxx value", func() {
|
|
| 161 |
+ g.By("starting a valid build with a directory")
|
|
| 162 |
+ out, err := oc.Run("start-build").Args("sample-build-binary", "--follow", "--wait", fmt.Sprintf("--from-dir=%s", exampleBuild)).Output()
|
|
| 163 |
+ g.By(fmt.Sprintf("verifying the build %q status", out))
|
|
| 164 |
+ o.Expect(err).NotTo(o.HaveOccurred()) |
|
| 165 |
+ o.Expect(out).To(o.ContainSubstring("Uploading directory"))
|
|
| 166 |
+ o.Expect(out).To(o.ContainSubstring("as binary input for the build ..."))
|
|
| 167 |
+ o.Expect(out).To(o.ContainSubstring("Your bundle is complete"))
|
|
| 168 |
+ |
|
| 169 |
+ err = exutil.WaitForABuild(oc.REST().Builds(oc.Namespace()), "sample-build-binary-1", exutil.CheckBuildSuccessFn, exutil.CheckBuildFailedFn) |
|
| 170 |
+ if err != nil {
|
|
| 171 |
+ exutil.DumpBuildLogs("sample-build-binary", oc)
|
|
| 172 |
+ } |
|
| 173 |
+ o.Expect(err).NotTo(o.HaveOccurred()) |
|
| 174 |
+ |
|
| 175 |
+ g.By("starting a build without a --from-xxxx value")
|
|
| 176 |
+ out, err = oc.Run("start-build").Args("sample-build-binary").Output()
|
|
| 177 |
+ o.Expect(err).To(o.HaveOccurred()) |
|
| 178 |
+ o.Expect(out).To(o.ContainSubstring("has no valid source inputs"))
|
|
| 179 |
+ |
|
| 180 |
+ g.By("starting a build from an existing binary build")
|
|
| 181 |
+ out, err = oc.Run("start-build").Args("sample-build-binary", fmt.Sprintf("--from-build=%s", "sample-build-binary-1")).Output()
|
|
| 182 |
+ o.Expect(err).To(o.HaveOccurred()) |
|
| 183 |
+ o.Expect(out).To(o.ContainSubstring("has no valid source inputs"))
|
|
| 184 |
+ |
|
| 185 |
+ }) |
|
| 158 | 186 |
}) |
| 159 | 187 |
|
| 160 | 188 |
g.Describe("cancelling build started by oc start-build --wait", func() {
|
| ... | ... |
@@ -53,6 +53,43 @@ |
| 53 | 53 |
"status": {
|
| 54 | 54 |
"lastVersion": 0 |
| 55 | 55 |
} |
| 56 |
+ }, |
|
| 57 |
+ {
|
|
| 58 |
+ "kind": "BuildConfig", |
|
| 59 |
+ "apiVersion": "v1", |
|
| 60 |
+ "metadata": {
|
|
| 61 |
+ "name": "sample-build-binary", |
|
| 62 |
+ "creationTimestamp": null |
|
| 63 |
+ }, |
|
| 64 |
+ "spec": {
|
|
| 65 |
+ "triggers": [ |
|
| 66 |
+ {
|
|
| 67 |
+ "type": "imageChange", |
|
| 68 |
+ "imageChange": {}
|
|
| 69 |
+ } |
|
| 70 |
+ ], |
|
| 71 |
+ "source": {
|
|
| 72 |
+ "type": "Binary", |
|
| 73 |
+ "binary": {}
|
|
| 74 |
+ }, |
|
| 75 |
+ "strategy": {
|
|
| 76 |
+ "type": "Docker", |
|
| 77 |
+ "dockerStrategy": {
|
|
| 78 |
+ "env": [ |
|
| 79 |
+ { "name": "FOO", "value": "test" },
|
|
| 80 |
+ { "name": "BAR", "value": "test" }
|
|
| 81 |
+ ], |
|
| 82 |
+ "from": {
|
|
| 83 |
+ "kind": "DockerImage", |
|
| 84 |
+ "name": "centos/ruby-22-centos7" |
|
| 85 |
+ } |
|
| 86 |
+ } |
|
| 87 |
+ }, |
|
| 88 |
+ "resources": {}
|
|
| 89 |
+ }, |
|
| 90 |
+ "status": {
|
|
| 91 |
+ "lastVersion": 0 |
|
| 92 |
+ } |
|
| 56 | 93 |
} |
| 57 | 94 |
] |
| 58 | 95 |
} |