Browse code

New-app/new-build support for pipeline buildconfigs

Jim Minter authored on 2016/11/10 22:03:36
Showing 27 changed files
... ...
@@ -115,8 +115,8 @@ If you provide source code, a new build will be automatically triggered. You can
115 115
     Search all templates, image streams, and Docker images that match the arguments provided.
116 116
 
117 117
 .PP
118
-\fB\-\-strategy\fP=""
119
-    Specify the build strategy to use if you don't want to detect (docker|source).
118
+\fB\-\-strategy\fP=
119
+    Specify the build strategy to use if you don't want to detect (docker|pipeline|source).
120 120
 
121 121
 .PP
122 122
 \fB\-\-template\fP=[]
... ...
@@ -103,8 +103,8 @@ Once the build configuration is created a new build will be automatically trigge
103 103
     Specify the file or directory to copy from the source image and its destination in the build directory. Format: [source]:[destination\-dir].
104 104
 
105 105
 .PP
106
-\fB\-\-strategy\fP=""
107
-    Specify the build strategy to use if you don't want to detect (docker|source).
106
+\fB\-\-strategy\fP=
107
+    Specify the build strategy to use if you don't want to detect (docker|pipeline|source).
108 108
 
109 109
 .PP
110 110
 \fB\-\-to\fP=""
... ...
@@ -115,8 +115,8 @@ If you provide source code, a new build will be automatically triggered. You can
115 115
     Search all templates, image streams, and Docker images that match the arguments provided.
116 116
 
117 117
 .PP
118
-\fB\-\-strategy\fP=""
119
-    Specify the build strategy to use if you don't want to detect (docker|source).
118
+\fB\-\-strategy\fP=
119
+    Specify the build strategy to use if you don't want to detect (docker|pipeline|source).
120 120
 
121 121
 .PP
122 122
 \fB\-\-template\fP=[]
... ...
@@ -103,8 +103,8 @@ Once the build configuration is created a new build will be automatically trigge
103 103
     Specify the file or directory to copy from the source image and its destination in the build directory. Format: [source]:[destination\-dir].
104 104
 
105 105
 .PP
106
-\fB\-\-strategy\fP=""
107
-    Specify the build strategy to use if you don't want to detect (docker|source).
106
+\fB\-\-strategy\fP=
107
+    Specify the build strategy to use if you don't want to detect (docker|pipeline|source).
108 108
 
109 109
 .PP
110 110
 \fB\-\-to\fP=""
... ...
@@ -34,6 +34,7 @@ import (
34 34
 	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
35 35
 	dockerutil "github.com/openshift/origin/pkg/cmd/util/docker"
36 36
 	configcmd "github.com/openshift/origin/pkg/config/cmd"
37
+	"github.com/openshift/origin/pkg/generate"
37 38
 	newapp "github.com/openshift/origin/pkg/generate/app"
38 39
 	newcmd "github.com/openshift/origin/pkg/generate/app/cmd"
39 40
 	"github.com/openshift/origin/pkg/generate/git"
... ...
@@ -170,7 +171,7 @@ func NewCmdNewApplication(name, baseName string, f *clientcmd.Factory, out, erro
170 170
 	cmd.Flags().StringSliceVar(&config.Groups, "group", config.Groups, "Indicate components that should be grouped together as <comp1>+<comp2>.")
171 171
 	cmd.Flags().StringArrayVarP(&config.Environment, "env", "e", config.Environment, "Specify a key-value pair for an environment variable to set into each container. This doesn't apply to objects created from a template, use parameters instead.")
172 172
 	cmd.Flags().StringVar(&config.Name, "name", "", "Set name to use for generated application artifacts")
173
-	cmd.Flags().StringVar(&config.Strategy, "strategy", "", "Specify the build strategy to use if you don't want to detect (docker|source).")
173
+	cmd.Flags().Var(&config.Strategy, "strategy", "Specify the build strategy to use if you don't want to detect (docker|pipeline|source).")
174 174
 	cmd.Flags().StringP("labels", "l", "", "Label to set in all resources for this application.")
175 175
 	cmd.Flags().BoolVar(&config.InsecureRegistry, "insecure-registry", false, "If true, indicates that the referenced Docker images are on insecure registries and should bypass certificate checking")
176 176
 	cmd.Flags().BoolVarP(&config.AsList, "list", "L", false, "List all local templates and image streams that can be used to create.")
... ...
@@ -505,6 +506,11 @@ func CompleteAppConfig(config *newcmd.AppConfig, f *clientcmd.Factory, c *cobra.
505 505
 	if len(config.SourceImage) == 0 && len(config.SourceImagePath) != 0 {
506 506
 		return kcmdutil.UsageError(c, "--source-image must be specified when --source-image-path is specified.")
507 507
 	}
508
+
509
+	if config.BinaryBuild && config.Strategy == generate.StrategyPipeline {
510
+		return kcmdutil.UsageError(c, "specifying binary builds and the pipeline strategy at the same time is not allowed.")
511
+	}
512
+
508 513
 	return nil
509 514
 }
510 515
 
... ...
@@ -72,7 +72,7 @@ func TestNewAppDefaultFlags(t *testing.T) {
72 72
 		},
73 73
 		"strategy": {
74 74
 			flagName:   "strategy",
75
-			defaultVal: config.Strategy,
75
+			defaultVal: "",
76 76
 		},
77 77
 		"labels": {
78 78
 			flagName:   "labels",
... ...
@@ -129,7 +129,7 @@ func NewCmdNewBuild(name, baseName string, f *clientcmd.Factory, in io.Reader, o
129 129
 	cmd.Flags().StringVar(&config.To, "to", "", "Push built images to this image stream tag (or Docker image repository if --to-docker is set).")
130 130
 	cmd.Flags().BoolVar(&config.OutputDocker, "to-docker", false, "Have the build output push to a Docker repository.")
131 131
 	cmd.Flags().StringArrayVarP(&config.Environment, "env", "e", config.Environment, "Specify a key-value pair for an environment variable to set into resulting image.")
132
-	cmd.Flags().StringVar(&config.Strategy, "strategy", "", "Specify the build strategy to use if you don't want to detect (docker|source).")
132
+	cmd.Flags().Var(&config.Strategy, "strategy", "Specify the build strategy to use if you don't want to detect (docker|pipeline|source).")
133 133
 	cmd.Flags().StringVarP(&config.Dockerfile, "dockerfile", "D", "", "Specify the contents of a Dockerfile to build directly, implies --strategy=docker. Pass '-' to read from STDIN.")
134 134
 	cmd.Flags().BoolVar(&config.BinaryBuild, "binary", false, "Instead of expecting a source URL, set the build to expect binary contents. Will disable triggers.")
135 135
 	cmd.Flags().StringP("labels", "l", "", "Label to set in all generated resources.")
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"strconv"
11 11
 	"strings"
12 12
 
13
+	"github.com/golang/glog"
13 14
 	"github.com/pborman/uuid"
14 15
 	kapi "k8s.io/kubernetes/pkg/api"
15 16
 	"k8s.io/kubernetes/pkg/api/unversioned"
... ...
@@ -18,6 +19,7 @@ import (
18 18
 
19 19
 	buildapi "github.com/openshift/origin/pkg/build/api"
20 20
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
21
+	"github.com/openshift/origin/pkg/generate"
21 22
 	"github.com/openshift/origin/pkg/generate/git"
22 23
 	imageapi "github.com/openshift/origin/pkg/image/api"
23 24
 	"github.com/openshift/origin/pkg/util"
... ...
@@ -193,13 +195,19 @@ func (r *SourceRef) BuildSource() (*buildapi.BuildSource, []buildapi.BuildTrigge
193 193
 
194 194
 // BuildStrategyRef is a reference to a build strategy
195 195
 type BuildStrategyRef struct {
196
-	IsDockerBuild bool
197
-	Base          *ImageRef
196
+	Strategy generate.Strategy
197
+	Base     *ImageRef
198 198
 }
199 199
 
200 200
 // BuildStrategy builds an OpenShift BuildStrategy from a BuildStrategyRef
201 201
 func (s *BuildStrategyRef) BuildStrategy(env Environment) (*buildapi.BuildStrategy, []buildapi.BuildTriggerPolicy) {
202
-	if s.IsDockerBuild {
202
+	switch s.Strategy {
203
+	case generate.StrategyPipeline:
204
+		return &buildapi.BuildStrategy{
205
+			JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{},
206
+		}, s.Base.BuildTriggers()
207
+
208
+	case generate.StrategyDocker:
203 209
 		var triggers []buildapi.BuildTriggerPolicy
204 210
 		strategy := &buildapi.DockerBuildStrategy{
205 211
 			Env: env.List(),
... ...
@@ -212,14 +220,18 @@ func (s *BuildStrategyRef) BuildStrategy(env Environment) (*buildapi.BuildStrate
212 212
 		return &buildapi.BuildStrategy{
213 213
 			DockerStrategy: strategy,
214 214
 		}, triggers
215
+
216
+	case generate.StrategySource:
217
+		return &buildapi.BuildStrategy{
218
+			SourceStrategy: &buildapi.SourceBuildStrategy{
219
+				From: s.Base.ObjectReference(),
220
+				Env:  env.List(),
221
+			},
222
+		}, s.Base.BuildTriggers()
215 223
 	}
216 224
 
217
-	return &buildapi.BuildStrategy{
218
-		SourceStrategy: &buildapi.SourceBuildStrategy{
219
-			From: s.Base.ObjectReference(),
220
-			Env:  env.List(),
221
-		},
222
-	}, s.Base.BuildTriggers()
225
+	glog.Error("BuildStrategy called with unknown strategy")
226
+	return nil, nil
223 227
 }
224 228
 
225 229
 // BuildRef is a reference to a build configuration
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"k8s.io/kubernetes/pkg/util/sets"
11 11
 
12 12
 	"github.com/openshift/origin/pkg/cmd/cli/describe"
13
+	"github.com/openshift/origin/pkg/generate"
13 14
 	"github.com/openshift/origin/pkg/generate/app"
14 15
 	imageapi "github.com/openshift/origin/pkg/image/api"
15 16
 )
... ...
@@ -148,16 +149,10 @@ func describeBuildPipelineWithImage(out io.Writer, ref app.ComponentReference, p
148 148
 				}
149 149
 				matches = append(matches, t.Platform)
150 150
 			}
151
-			if len(matches) > 0 && !pipeline.Build.Strategy.IsDockerBuild {
151
+			if len(matches) > 0 && pipeline.Build.Strategy.Strategy == generate.StrategySource {
152 152
 				fmt.Fprintf(out, "    * The source repository appears to match: %s\n", strings.Join(matches, ", "))
153 153
 			}
154 154
 		}
155
-		var strategy string
156
-		if pipeline.Build.Strategy.IsDockerBuild {
157
-			strategy = "Docker"
158
-		} else {
159
-			strategy = "source"
160
-		}
161 155
 		noSource := false
162 156
 		var source string
163 157
 		switch s := pipeline.Build.Source; {
... ...
@@ -175,7 +170,7 @@ func describeBuildPipelineWithImage(out io.Writer, ref app.ComponentReference, p
175 175
 			source = "<unknown>"
176 176
 		}
177 177
 
178
-		fmt.Fprintf(out, "    * A %s build using %s will be created\n", strategy, source)
178
+		fmt.Fprintf(out, "    * A %s build using %s will be created\n", pipeline.Build.Strategy.Strategy, source)
179 179
 		if buildOut, err := pipeline.Build.Output.BuildOutput(); err == nil && buildOut != nil && buildOut.To != nil {
180 180
 			switch to := buildOut.To; {
181 181
 			case to.Kind == "ImageStreamTag":
... ...
@@ -28,8 +28,10 @@ import (
28 28
 	"github.com/openshift/origin/pkg/client"
29 29
 	cmdutil "github.com/openshift/origin/pkg/cmd/util"
30 30
 	"github.com/openshift/origin/pkg/dockerregistry"
31
+	"github.com/openshift/origin/pkg/generate"
31 32
 	"github.com/openshift/origin/pkg/generate/app"
32 33
 	"github.com/openshift/origin/pkg/generate/dockerfile"
34
+	"github.com/openshift/origin/pkg/generate/jenkinsfile"
33 35
 	"github.com/openshift/origin/pkg/generate/source"
34 36
 	imageapi "github.com/openshift/origin/pkg/image/api"
35 37
 	outil "github.com/openshift/origin/pkg/util"
... ...
@@ -44,10 +46,6 @@ const (
44 44
 	GeneratedByNewBuild  = "OpenShiftNewBuild"
45 45
 )
46 46
 
47
-// ErrNoDockerfileDetected is the error returned when the requested build strategy is Docker
48
-// and no Dockerfile is detected in the repository.
49
-var ErrNoDockerfileDetected = errors.New("No Dockerfile was found in the repository and the requested build strategy is 'docker'")
50
-
51 47
 // GenerationInputs control how new-app creates output
52 48
 // TODO: split these into finer grained structs
53 49
 type GenerationInputs struct {
... ...
@@ -59,7 +57,7 @@ type GenerationInputs struct {
59 59
 
60 60
 	InsecureRegistry bool
61 61
 
62
-	Strategy string
62
+	Strategy generate.Strategy
63 63
 
64 64
 	Name     string
65 65
 	To       string
... ...
@@ -161,8 +159,9 @@ func NewAppConfig() *AppConfig {
161 161
 	return &AppConfig{
162 162
 		Resolvers: Resolvers{
163 163
 			Detector: app.SourceRepositoryEnumerator{
164
-				Detectors: source.DefaultDetectors,
165
-				Tester:    dockerfile.NewTester(),
164
+				Detectors:         source.DefaultDetectors,
165
+				DockerfileTester:  dockerfile.NewTester(),
166
+				JenkinsfileTester: jenkinsfile.NewTester(),
166 167
 			},
167 168
 		},
168 169
 	}
... ...
@@ -249,18 +248,18 @@ func (c *AppConfig) AddArguments(args []string) []string {
249 249
 }
250 250
 
251 251
 // validateBuilders confirms that all images associated with components that are to be built,
252
-// are builders (or we're using a docker strategy).
252
+// are builders (or we're using a non-source strategy).
253 253
 func (c *AppConfig) validateBuilders(components app.ComponentReferences) error {
254
-	if len(c.Strategy) != 0 {
254
+	if c.Strategy != generate.StrategyUnspecified {
255 255
 		return nil
256 256
 	}
257 257
 	errs := []error{}
258 258
 	for _, ref := range components {
259 259
 		input := ref.Input()
260 260
 		// if we're supposed to build this thing, and the image/imagestream we've matched it to did not come from an explicit CLI argument,
261
-		// and the image/imagestream we matched to is not explicitly an s2i builder, and we're not doing a docker-type build, warn the user
261
+		// and the image/imagestream we matched to is not explicitly an s2i builder, and we're doing a source-type build, warn the user
262 262
 		// that this probably won't work and force them to declare their intention explicitly.
263
-		if input.ExpectToBuild && input.ResolvedMatch != nil && !app.IsBuilderMatch(input.ResolvedMatch) && input.Uses != nil && !input.Uses.IsDockerBuild() {
263
+		if input.ExpectToBuild && input.ResolvedMatch != nil && !app.IsBuilderMatch(input.ResolvedMatch) && input.Uses != nil && input.Uses.GetStrategy() == generate.StrategySource {
264 264
 			errs = append(errs, fmt.Errorf("the image match %q for source repository %q does not appear to be a source-to-image builder.\n\n- to attempt to use this image as a source builder, pass \"--strategy=source\"\n- to use it as a base image for a Docker build, pass \"--strategy=docker\"", input.ResolvedMatch.Name, input.Uses))
265 265
 			continue
266 266
 		}
... ...
@@ -275,13 +274,6 @@ func validateEnforcedName(name string) error {
275 275
 	return nil
276 276
 }
277 277
 
278
-func validateStrategyName(name string) error {
279
-	if name != "docker" && name != "source" {
280
-		return fmt.Errorf("invalid strategy: %s. Must be 'docker' or 'source'.", name)
281
-	}
282
-	return nil
283
-}
284
-
285 278
 func validateOutputImageReference(ref string) error {
286 279
 	if _, err := imageapi.ParseDockerImageReference(ref); err != nil {
287 280
 		return fmt.Errorf("invalid output image reference: %s", ref)
... ...
@@ -304,7 +296,7 @@ func (c *AppConfig) buildPipelines(components app.ComponentReferences, environme
304 304
 			switch {
305 305
 			case refInput.ExpectToBuild:
306 306
 				glog.V(4).Infof("will add %q secrets into a build for a source build of %q", strings.Join(c.Secrets, ","), refInput.Uses)
307
-				if err := refInput.Uses.AddBuildSecrets(c.Secrets, refInput.Uses.IsDockerBuild()); err != nil {
307
+				if err := refInput.Uses.AddBuildSecrets(c.Secrets); err != nil {
308 308
 					return nil, fmt.Errorf("unable to add build secrets %q: %v", strings.Join(c.Secrets, ","), err)
309 309
 				}
310 310
 
... ...
@@ -317,7 +309,7 @@ func (c *AppConfig) buildPipelines(components app.ComponentReferences, environme
317 317
 					if err != nil {
318 318
 						return nil, fmt.Errorf("can't build %q: %v", from, err)
319 319
 					}
320
-					if !inputImage.AsImageStream && from != "scratch" {
320
+					if !inputImage.AsImageStream && from != "scratch" && (refInput.Uses == nil || refInput.Uses.GetStrategy() != generate.StrategyPipeline) {
321 321
 						msg := "Could not find an image stream match for %q. Make sure that a Docker image with that tag is available on the node for the build to succeed."
322 322
 						glog.Warningf(msg, from)
323 323
 					}
... ...
@@ -351,6 +343,12 @@ func (c *AppConfig) buildPipelines(components app.ComponentReferences, environme
351 351
 			if c.NoOutput {
352 352
 				pipeline.Build.Output = nil
353 353
 			}
354
+			if refInput.Uses != nil && refInput.Uses.GetStrategy() == generate.StrategyPipeline {
355
+				pipeline.Build.Output = nil
356
+				pipeline.Deployment = nil
357
+				pipeline.Image = nil
358
+				pipeline.InputImage = nil
359
+			}
354 360
 			common = append(common, pipeline)
355 361
 			if err := common.Reduce(); err != nil {
356 362
 				return nil, fmt.Errorf("can't create a pipeline from %s: %v", common, err)
... ...
@@ -613,12 +611,6 @@ func (c *AppConfig) Run() (*AppResult, error) {
613 613
 		}
614 614
 	}
615 615
 
616
-	if len(c.Strategy) > 0 {
617
-		if err := validateStrategyName(c.Strategy); err != nil {
618
-			return nil, err
619
-		}
620
-	}
621
-
622 616
 	if err := optionallyValidateExposedPorts(c, repositories); err != nil {
623 617
 		return nil, err
624 618
 	}
... ...
@@ -901,7 +893,7 @@ func optionallyValidateExposedPorts(config *AppConfig, repositories app.SourceRe
901 901
 		return nil
902 902
 	}
903 903
 
904
-	if len(config.Strategy) > 0 && config.Strategy != "docker" {
904
+	if config.Strategy != generate.StrategyUnspecified && config.Strategy != generate.StrategyDocker {
905 905
 		return nil
906 906
 	}
907 907
 
... ...
@@ -15,6 +15,7 @@ import (
15 15
 
16 16
 	buildapi "github.com/openshift/origin/pkg/build/api"
17 17
 	client "github.com/openshift/origin/pkg/client/testclient"
18
+	"github.com/openshift/origin/pkg/generate"
18 19
 	"github.com/openshift/origin/pkg/generate/app"
19 20
 	image "github.com/openshift/origin/pkg/image/api"
20 21
 	templateapi "github.com/openshift/origin/pkg/template/api"
... ...
@@ -339,7 +340,7 @@ func mockSourceRepositories(t *testing.T, file string) []*app.SourceRepository {
339 339
 		"https://github.com/openshift/ruby-hello-world.git",
340 340
 		file,
341 341
 	} {
342
-		s, err := app.NewSourceRepository(location)
342
+		s, err := app.NewSourceRepository(location, generate.StrategySource)
343 343
 		if err != nil {
344 344
 			t.Fatal(err)
345 345
 		}
... ...
@@ -356,11 +357,10 @@ func TestBuildPipelinesWithUnresolvedImage(t *testing.T) {
356 356
 		t.Fatal(err)
357 357
 	}
358 358
 
359
-	sourceRepo, err := app.NewSourceRepository("https://github.com/foo/bar.git")
359
+	sourceRepo, err := app.NewSourceRepository("https://github.com/foo/bar.git", generate.StrategyDocker)
360 360
 	if err != nil {
361 361
 		t.Fatal(err)
362 362
 	}
363
-	sourceRepo.BuildWithDocker()
364 363
 	sourceRepo.SetInfo(&app.SourceRepositoryInfo{
365 364
 		Dockerfile: dockerFile,
366 365
 	})
... ...
@@ -509,15 +509,15 @@ func TestBuildOutputCycleWithFollowingTag(t *testing.T) {
509 509
 
510 510
 func TestAllowedNonNumericExposedPorts(t *testing.T) {
511 511
 	tests := []struct {
512
-		strategy             string
512
+		strategy             generate.Strategy
513 513
 		allowNonNumericPorts bool
514 514
 	}{
515 515
 		{
516
-			strategy:             "",
516
+			strategy:             generate.StrategyUnspecified,
517 517
 			allowNonNumericPorts: true,
518 518
 		},
519 519
 		{
520
-			strategy:             "source",
520
+			strategy:             generate.StrategySource,
521 521
 			allowNonNumericPorts: false,
522 522
 		},
523 523
 	}
... ...
@@ -543,15 +543,15 @@ func TestAllowedNonNumericExposedPorts(t *testing.T) {
543 543
 
544 544
 func TestDisallowedNonNumericExposedPorts(t *testing.T) {
545 545
 	tests := []struct {
546
-		strategy             string
546
+		strategy             generate.Strategy
547 547
 		allowNonNumericPorts bool
548 548
 	}{
549 549
 		{
550
-			strategy:             "",
550
+			strategy:             generate.StrategyUnspecified,
551 551
 			allowNonNumericPorts: false,
552 552
 		},
553 553
 		{
554
-			strategy:             "docker",
554
+			strategy:             generate.StrategyDocker,
555 555
 			allowNonNumericPorts: false,
556 556
 		},
557 557
 	}
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"github.com/golang/glog"
9 9
 	kutilerrors "k8s.io/kubernetes/pkg/util/errors"
10 10
 
11
+	"github.com/openshift/origin/pkg/generate"
11 12
 	"github.com/openshift/origin/pkg/generate/app"
12 13
 	dockerfileutil "github.com/openshift/origin/pkg/util/docker/dockerfile"
13 14
 )
... ...
@@ -53,6 +54,10 @@ func (r *Resolvers) DockerfileResolver() app.Resolver {
53 53
 	return resolver
54 54
 }
55 55
 
56
+func (r *Resolvers) PipelineResolver() app.Resolver {
57
+	return app.PipelineResolver{}
58
+}
59
+
56 60
 // TODO: why does this differ from ImageSourceResolver?
57 61
 func (r *Resolvers) SourceResolver() app.Resolver {
58 62
 	resolver := app.PerfectMatchWeightedResolver{}
... ...
@@ -110,7 +115,7 @@ func Resolve(r *Resolvers, c *ComponentInputs, g *GenerationInputs) (*ResolvedCo
110 110
 		repo.SetContextDir(g.ContextDir)
111 111
 	}
112 112
 
113
-	if len(g.Strategy) != 0 && len(repositories) == 0 && !g.BinaryBuild {
113
+	if g.Strategy != generate.StrategyUnspecified && len(repositories) == 0 && !g.BinaryBuild {
114 114
 		return nil, errors.New("when --strategy is specified you must provide at least one source code location")
115 115
 	}
116 116
 
... ...
@@ -154,7 +159,7 @@ func Resolve(r *Resolvers, c *ComponentInputs, g *GenerationInputs) (*ResolvedCo
154 154
 	}
155 155
 
156 156
 	// For source repos that are not yet linked to a component, create components
157
-	sourceComponents, err := AddMissingComponentsToRefBuilder(b, repositories.NotUsed(), r.DockerfileResolver(), r.SourceResolver(), g)
157
+	sourceComponents, err := AddMissingComponentsToRefBuilder(b, repositories.NotUsed(), r.DockerfileResolver(), r.SourceResolver(), r.PipelineResolver(), g)
158 158
 	if err != nil {
159 159
 		return nil, err
160 160
 	}
... ...
@@ -177,16 +182,17 @@ func Resolve(r *Resolvers, c *ComponentInputs, g *GenerationInputs) (*ResolvedCo
177 177
 // AddSourceRepositoriesToRefBuilder adds the provided repositories to the reference builder, identifies which
178 178
 // should be built using Docker, and then returns the full list of source repositories.
179 179
 func AddSourceRepositoriesToRefBuilder(b *app.ReferenceBuilder, repos []string, g *GenerationInputs) (app.SourceRepositories, error) {
180
+	strategy := g.Strategy
181
+	if strategy == generate.StrategyUnspecified {
182
+		strategy = generate.StrategySource
183
+	}
180 184
 	for _, s := range repos {
181
-		if repo, ok := b.AddSourceRepository(s); ok {
185
+		if repo, ok := b.AddSourceRepository(s, strategy); ok {
182 186
 			repo.SetContextDir(g.ContextDir)
183
-			if g.Strategy == "docker" {
184
-				repo.BuildWithDocker()
185
-			}
186 187
 		}
187 188
 	}
188 189
 	if len(g.Dockerfile) > 0 {
189
-		if len(g.Strategy) != 0 && g.Strategy != "docker" {
190
+		if g.Strategy != generate.StrategyUnspecified && g.Strategy != generate.StrategyDocker {
190 191
 			return nil, errors.New("when directly referencing a Dockerfile, the strategy must must be 'docker'")
191 192
 		}
192 193
 		if err := AddDockerfileToSourceRepositories(b, g.Dockerfile); err != nil {
... ...
@@ -230,15 +236,25 @@ func AddDockerfileToSourceRepositories(b *app.ReferenceBuilder, dockerfile strin
230 230
 func DetectSource(repositories []*app.SourceRepository, d app.Detector, g *GenerationInputs) error {
231 231
 	errs := []error{}
232 232
 	for _, repo := range repositories {
233
-		err := repo.Detect(d, g.Strategy == "docker")
233
+		err := repo.Detect(d, g.Strategy == generate.StrategyDocker || g.Strategy == generate.StrategyPipeline)
234 234
 		if err != nil {
235
-			if g.Strategy == "docker" && err == app.ErrNoLanguageDetected {
236
-				errs = append(errs, ErrNoDockerfileDetected)
237
-			} else {
238
-				errs = append(errs, err)
239
-			}
235
+			errs = append(errs, err)
240 236
 			continue
241 237
 		}
238
+		switch g.Strategy {
239
+		case generate.StrategyDocker:
240
+			if repo.Info().Dockerfile == nil {
241
+				errs = append(errs, errors.New("No Dockerfile was found in the repository and the requested build strategy is 'docker'"))
242
+			}
243
+		case generate.StrategyPipeline:
244
+			if !repo.Info().Jenkinsfile {
245
+				errs = append(errs, errors.New("No Jenkinsfile was found in the repository and the requested build strategy is 'pipeline'"))
246
+			}
247
+		default:
248
+			if repo.Info().Dockerfile == nil && !repo.Info().Jenkinsfile && len(repo.Info().Types) == 0 {
249
+				errs = append(errs, errors.New("No language matched the source repository"))
250
+			}
251
+		}
242 252
 	}
243 253
 	return kutilerrors.NewAggregate(errs)
244 254
 }
... ...
@@ -354,7 +370,7 @@ func AddImageSourceRepository(sourceRepos app.SourceRepositories, r app.Resolver
354 354
 		sourceRepos[0].SetSourceImage(compRef)
355 355
 		sourceRepos[0].SetSourceImagePath(sourcePath, destPath)
356 356
 	default:
357
-		return nil, nil, errors.New("--image-source cannot be used with multiple source repositories")
357
+		return nil, nil, errors.New("--source-image cannot be used with multiple source repositories")
358 358
 	}
359 359
 
360 360
 	return compRef, sourceRepos, nil
... ...
@@ -386,13 +402,14 @@ func InferBuildTypes(components app.ComponentReferences, g *GenerationInputs) (a
386 386
 		}
387 387
 		input.ResolvedMatch.GeneratorInput = generatorInput
388 388
 
389
-		// if the strategy is explicitly Docker, all repos should assume docker
390
-		if g.Strategy == "docker" && input.Uses != nil {
391
-			input.Uses.BuildWithDocker()
389
+		// if the strategy is set explicitly, apply it to all repos.
390
+		// for example, this affects repos specified in the form image~source.
391
+		if g.Strategy != generate.StrategyUnspecified && input.Uses != nil {
392
+			input.Uses.SetStrategy(g.Strategy)
392 393
 		}
393 394
 
394 395
 		// if we are expecting build inputs, or get a build input when strategy is not docker, expect to build
395
-		if g.ExpectToBuild || (input.ResolvedMatch.Builder && g.Strategy != "docker") {
396
+		if g.ExpectToBuild || (input.ResolvedMatch.Builder && g.Strategy != generate.StrategyDocker) {
396 397
 			input.ExpectToBuild = true
397 398
 		}
398 399
 
... ...
@@ -403,7 +420,7 @@ func InferBuildTypes(components app.ComponentReferences, g *GenerationInputs) (a
403 403
 			continue
404 404
 		}
405 405
 	}
406
-	if len(components) == 0 && g.BinaryBuild && g.Strategy == "source" {
406
+	if len(components) == 0 && g.BinaryBuild && g.Strategy == generate.StrategySource {
407 407
 		return nil, errors.New("you must provide a builder image when using the source strategy with a binary build")
408 408
 	}
409 409
 	if len(components) == 0 && g.BinaryBuild {
... ...
@@ -464,11 +481,12 @@ func EnsureHasSource(components app.ComponentReferences, repositories app.Source
464 464
 				if input.Uses != nil {
465 465
 					continue
466 466
 				}
467
-				repo := app.NewBinarySourceRepository()
467
+				strategy := generate.StrategySource
468 468
 				isBuilder := input.ResolvedMatch != nil && input.ResolvedMatch.Builder
469
-				if g.Strategy == "docker" || (len(g.Strategy) == 0 && !isBuilder) {
470
-					repo.BuildWithDocker()
469
+				if g.Strategy == generate.StrategyDocker || (g.Strategy == generate.StrategyUnspecified && !isBuilder) {
470
+					strategy = generate.StrategyDocker
471 471
 				}
472
+				repo := app.NewBinarySourceRepository(strategy)
472 473
 				input.Use(repo)
473 474
 				repo.UsedBy(input)
474 475
 				input.ExpectToBuild = true
... ...
@@ -488,7 +506,7 @@ func EnsureHasSource(components app.ComponentReferences, repositories app.Source
488 488
 // builder. These components have already gone through source code detection and have a SourceRepositoryInfo attached
489 489
 // to them.
490 490
 func AddMissingComponentsToRefBuilder(
491
-	b *app.ReferenceBuilder, repositories app.SourceRepositories, dockerfileResolver, sourceResolver app.Resolver,
491
+	b *app.ReferenceBuilder, repositories app.SourceRepositories, dockerfileResolver, sourceResolver, pipelineResolver app.Resolver,
492 492
 	g *GenerationInputs,
493 493
 ) (app.ComponentReferences, error) {
494 494
 	errs := []error{}
... ...
@@ -499,7 +517,7 @@ func AddMissingComponentsToRefBuilder(
499 499
 		case info == nil:
500 500
 			errs = append(errs, fmt.Errorf("source not detected for repository %q", repo))
501 501
 			continue
502
-		case info.Dockerfile != nil && (len(g.Strategy) == 0 || g.Strategy == "docker"):
502
+		case info.Dockerfile != nil && (g.Strategy == generate.StrategyUnspecified || g.Strategy == generate.StrategyDocker):
503 503
 			node := info.Dockerfile.AST()
504 504
 			baseImage := dockerfileutil.LastBaseImage(node)
505 505
 			if baseImage == "" {
... ...
@@ -511,7 +529,18 @@ func AddMissingComponentsToRefBuilder(
511 511
 				input.Use(repo)
512 512
 				input.ExpectToBuild = true
513 513
 				repo.UsedBy(input)
514
-				repo.BuildWithDocker()
514
+				repo.SetStrategy(generate.StrategyDocker)
515
+				return input
516
+			})
517
+			result = append(result, refs...)
518
+
519
+		case info.Jenkinsfile && (g.Strategy == generate.StrategyUnspecified || g.Strategy == generate.StrategyPipeline):
520
+			refs := b.AddComponents([]string{"pipeline"}, func(input *app.ComponentInput) app.ComponentReference {
521
+				input.Resolver = pipelineResolver
522
+				input.Use(repo)
523
+				input.ExpectToBuild = true
524
+				repo.UsedBy(input)
525
+				repo.SetStrategy(generate.StrategyPipeline)
515 526
 				return input
516 527
 			})
517 528
 			result = append(result, refs...)
... ...
@@ -5,6 +5,8 @@ import (
5 5
 	"sort"
6 6
 	"strings"
7 7
 
8
+	"github.com/openshift/origin/pkg/generate"
9
+
8 10
 	"k8s.io/kubernetes/pkg/util/errors"
9 11
 )
10 12
 
... ...
@@ -205,7 +207,7 @@ func (r *ReferenceBuilder) AddComponents(inputs []string, fn func(*ComponentInpu
205 205
 			input.GroupID = r.groupID
206 206
 			ref := fn(input)
207 207
 			if len(repo) != 0 {
208
-				repository, ok := r.AddSourceRepository(repo)
208
+				repository, ok := r.AddSourceRepository(repo, generate.StrategySource)
209 209
 				if !ok {
210 210
 					continue
211 211
 				}
... ...
@@ -251,13 +253,13 @@ func (r *ReferenceBuilder) AddGroups(inputs []string) {
251 251
 }
252 252
 
253 253
 // AddSourceRepository resolves the input to an actual source repository
254
-func (r *ReferenceBuilder) AddSourceRepository(input string) (*SourceRepository, bool) {
254
+func (r *ReferenceBuilder) AddSourceRepository(input string, strategy generate.Strategy) (*SourceRepository, bool) {
255 255
 	for _, existing := range r.repos {
256 256
 		if input == existing.location {
257 257
 			return existing, true
258 258
 		}
259 259
 	}
260
-	source, err := NewSourceRepository(input)
260
+	source, err := NewSourceRepository(input, strategy)
261 261
 	if err != nil {
262 262
 		r.errs = append(r.errs, err)
263 263
 		return nil, false
... ...
@@ -197,6 +197,19 @@ func (r UniqueExactOrInexactMatchResolver) Resolve(value string) (*ComponentMatc
197 197
 	}
198 198
 }
199 199
 
200
+// PipelineResolver returns a dummy ComponentMatch for any value input.  It is
201
+// used to provide a dummy component for for the pipeline/Jenkinsfile strategy.
202
+type PipelineResolver struct {
203
+}
204
+
205
+// Resolve returns a dummy ComponentMatch for any value input.
206
+func (r PipelineResolver) Resolve(value string) (*ComponentMatch, error) {
207
+	return &ComponentMatch{
208
+		Value:     value,
209
+		LocalOnly: true,
210
+	}, nil
211
+}
212
+
200 213
 // MultiSimpleSearcher is a set of searchers
201 214
 type MultiSimpleSearcher []Searcher
202 215
 
... ...
@@ -10,6 +10,7 @@ import (
10 10
 
11 11
 	buildapi "github.com/openshift/origin/pkg/build/api"
12 12
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
13
+	"github.com/openshift/origin/pkg/generate"
13 14
 	imageapi "github.com/openshift/origin/pkg/image/api"
14 15
 )
15 16
 
... ...
@@ -55,7 +56,7 @@ func TestBuildConfigOutput(t *testing.T) {
55 55
 	for i, test := range tests {
56 56
 		output.AsImageStream = test.asImageStream
57 57
 		source := &SourceRef{URL: url}
58
-		strategy := &BuildStrategyRef{IsDockerBuild: false, Base: base}
58
+		strategy := &BuildStrategyRef{Strategy: generate.StrategySource, Base: base}
59 59
 		build := &BuildRef{Source: source, Output: output, Strategy: strategy}
60 60
 		config, err := build.BuildConfig()
61 61
 		if err != nil {
... ...
@@ -15,6 +15,7 @@ import (
15 15
 
16 16
 	build "github.com/openshift/origin/pkg/build/api"
17 17
 	deploy "github.com/openshift/origin/pkg/deploy/api"
18
+	"github.com/openshift/origin/pkg/generate"
18 19
 	image "github.com/openshift/origin/pkg/image/api"
19 20
 	route "github.com/openshift/origin/pkg/route/api"
20 21
 	"github.com/openshift/origin/pkg/util/docker/dockerfile"
... ...
@@ -90,7 +91,7 @@ func (pb *pipelineBuilder) NewBuildPipeline(from string, input *ImageRef, source
90 90
 	source.Name = name
91 91
 
92 92
 	// Append any exposed ports from Dockerfile to input image
93
-	if sourceRepository.IsDockerBuild() && sourceRepository.Info() != nil {
93
+	if sourceRepository.GetStrategy() == generate.StrategyDocker && sourceRepository.Info() != nil {
94 94
 		node := sourceRepository.Info().Dockerfile.AST()
95 95
 		ports := dockerfile.LastExposedPorts(node)
96 96
 		if len(ports) > 0 {
... ...
@@ -14,7 +14,7 @@ import (
14 14
 	"github.com/golang/glog"
15 15
 
16 16
 	buildapi "github.com/openshift/origin/pkg/build/api"
17
-	"github.com/openshift/origin/pkg/generate/dockerfile"
17
+	"github.com/openshift/origin/pkg/generate"
18 18
 	"github.com/openshift/origin/pkg/generate/git"
19 19
 	"github.com/openshift/origin/pkg/generate/source"
20 20
 	s2iapi "github.com/openshift/source-to-image/pkg/api"
... ...
@@ -99,7 +99,7 @@ type SourceRepository struct {
99 99
 	sourceImageTo   string
100 100
 
101 101
 	usedBy           []ComponentReference
102
-	buildWithDocker  bool
102
+	strategy         generate.Strategy
103 103
 	ignoreRepository bool
104 104
 	binary           bool
105 105
 
... ...
@@ -110,7 +110,7 @@ type SourceRepository struct {
110 110
 
111 111
 // NewSourceRepository creates a reference to a local or remote source code repository from
112 112
 // a URL or path.
113
-func NewSourceRepository(s string) (*SourceRepository, error) {
113
+func NewSourceRepository(s string, strategy generate.Strategy) (*SourceRepository, error) {
114 114
 	location, err := git.ParseRepository(s)
115 115
 	if err != nil {
116 116
 		return nil, err
... ...
@@ -119,13 +119,14 @@ func NewSourceRepository(s string) (*SourceRepository, error) {
119 119
 	return &SourceRepository{
120 120
 		location: s,
121 121
 		url:      *location,
122
+		strategy: strategy,
122 123
 	}, nil
123 124
 }
124 125
 
125 126
 // NewSourceRepositoryWithDockerfile creates a reference to a local source code repository with
126 127
 // the provided relative Dockerfile path (defaults to "Dockerfile").
127 128
 func NewSourceRepositoryWithDockerfile(s, dockerfilePath string) (*SourceRepository, error) {
128
-	r, err := NewSourceRepository(s)
129
+	r, err := NewSourceRepository(s, generate.StrategyDocker)
129 130
 	if err != nil {
130 131
 		return nil, err
131 132
 	}
... ...
@@ -148,6 +149,7 @@ func NewSourceRepositoryWithDockerfile(s, dockerfilePath string) (*SourceReposit
148 148
 func NewSourceRepositoryForDockerfile(contents string) (*SourceRepository, error) {
149 149
 	s := &SourceRepository{
150 150
 		ignoreRepository: true,
151
+		strategy:         generate.StrategyDocker,
151 152
 	}
152 153
 	err := s.AddDockerfile(contents)
153 154
 	return s, err
... ...
@@ -155,10 +157,11 @@ func NewSourceRepositoryForDockerfile(contents string) (*SourceRepository, error
155 155
 
156 156
 // NewBinarySourceRepository creates a source repository that is configured for binary
157 157
 // input.
158
-func NewBinarySourceRepository() *SourceRepository {
158
+func NewBinarySourceRepository(strategy generate.Strategy) *SourceRepository {
159 159
 	return &SourceRepository{
160 160
 		binary:           true,
161 161
 		ignoreRepository: true,
162
+		strategy:         strategy,
162 163
 	}
163 164
 }
164 165
 
... ...
@@ -171,6 +174,7 @@ func NewImageSourceRepository(compRef ComponentReference, from, to string) *Sour
171 171
 		sourceImageTo:    to,
172 172
 		ignoreRepository: true,
173 173
 		location:         compRef.Input().From,
174
+		strategy:         generate.StrategySource,
174 175
 	}
175 176
 }
176 177
 
... ...
@@ -189,14 +193,14 @@ func (r *SourceRepository) InUse() bool {
189 189
 	return len(r.usedBy) > 0
190 190
 }
191 191
 
192
-// BuildWithDocker specifies that the source repository was built with Docker
193
-func (r *SourceRepository) BuildWithDocker() {
194
-	r.buildWithDocker = true
192
+// SetStrategy sets the source repository strategy
193
+func (r *SourceRepository) SetStrategy(strategy generate.Strategy) {
194
+	r.strategy = strategy
195 195
 }
196 196
 
197
-// IsDockerBuild checks if the source repository was built with Docker
198
-func (r *SourceRepository) IsDockerBuild() bool {
199
-	return r.buildWithDocker
197
+// GetStrategy returns the source repository strategy
198
+func (r *SourceRepository) GetStrategy() generate.Strategy {
199
+	return r.strategy
200 200
 }
201 201
 
202 202
 func (r *SourceRepository) String() string {
... ...
@@ -377,7 +381,7 @@ func (r *SourceRepository) AddDockerfile(contents string) error {
377 377
 		r.info = &SourceRepositoryInfo{}
378 378
 	}
379 379
 	r.info.Dockerfile = dockerfile
380
-	r.buildWithDocker = true
380
+	r.SetStrategy(generate.StrategyDocker)
381 381
 	r.forceAddDockerfile = true
382 382
 	return nil
383 383
 }
... ...
@@ -385,7 +389,7 @@ func (r *SourceRepository) AddDockerfile(contents string) error {
385 385
 // AddBuildSecrets adds the defined secrets into a build. The input format for
386 386
 // the secrets is "<secretName>:<destinationDir>". The destinationDir is
387 387
 // optional and when not specified the default is the current working directory.
388
-func (r *SourceRepository) AddBuildSecrets(secrets []string, isDockerBuild bool) error {
388
+func (r *SourceRepository) AddBuildSecrets(secrets []string) error {
389 389
 	injections := s2iapi.VolumeList{}
390 390
 	r.secrets = []buildapi.SecretBuildSource{}
391 391
 	for _, in := range secrets {
... ...
@@ -402,7 +406,7 @@ func (r *SourceRepository) AddBuildSecrets(secrets []string, isDockerBuild bool)
402 402
 		return false
403 403
 	}
404 404
 	for _, in := range injections {
405
-		if isDockerBuild && filepath.IsAbs(in.Destination) {
405
+		if r.GetStrategy() == generate.StrategyDocker && filepath.IsAbs(in.Destination) {
406 406
 			return fmt.Errorf("for the docker strategy, the secret destination directory %q must be a relative path", in.Destination)
407 407
 		}
408 408
 		if len(validation.ValidateSecretName(in.Source, false)) != 0 {
... ...
@@ -443,9 +447,10 @@ func (rr SourceRepositories) NotUsed() SourceRepositories {
443 443
 
444 444
 // SourceRepositoryInfo contains info about a source repository
445 445
 type SourceRepositoryInfo struct {
446
-	Path       string
447
-	Types      []SourceLanguageType
448
-	Dockerfile Dockerfile
446
+	Path        string
447
+	Types       []SourceLanguageType
448
+	Dockerfile  Dockerfile
449
+	Jenkinsfile bool
449 450
 }
450 451
 
451 452
 // Terms returns which languages the source repository was
... ...
@@ -482,23 +487,20 @@ type Detector interface {
482 482
 
483 483
 // SourceRepositoryEnumerator implements the Detector interface
484 484
 type SourceRepositoryEnumerator struct {
485
-	Detectors source.Detectors
486
-	Tester    dockerfile.Tester
485
+	Detectors         source.Detectors
486
+	DockerfileTester  generate.Tester
487
+	JenkinsfileTester generate.Tester
487 488
 }
488 489
 
489
-// ErrNoLanguageDetected is the error returned when no language can be detected by all
490
-// source code detectors.
491
-var ErrNoLanguageDetected = errors.New("No language matched the source repository")
492
-
493 490
 // Detect extracts source code information about the provided source repository
494
-func (e SourceRepositoryEnumerator) Detect(dir string, dockerStrategy bool) (*SourceRepositoryInfo, error) {
491
+func (e SourceRepositoryEnumerator) Detect(dir string, noSourceDetection bool) (*SourceRepositoryInfo, error) {
495 492
 	info := &SourceRepositoryInfo{
496 493
 		Path: dir,
497 494
 	}
498 495
 
499 496
 	// no point in doing source-type detection if the requested build strategy
500
-	// is docker
501
-	if !dockerStrategy {
497
+	// is docker or pipeline
498
+	if !noSourceDetection {
502 499
 		for _, d := range e.Detectors {
503 500
 			if detected, ok := d(dir); ok {
504 501
 				info.Types = append(info.Types, SourceLanguageType{
... ...
@@ -508,17 +510,17 @@ func (e SourceRepositoryEnumerator) Detect(dir string, dockerStrategy bool) (*So
508 508
 			}
509 509
 		}
510 510
 	}
511
-	if path, ok, err := e.Tester.Has(dir); err == nil && ok {
511
+	if path, ok, err := e.DockerfileTester.Has(dir); err == nil && ok {
512 512
 		dockerfile, err := NewDockerfileFromFile(path)
513 513
 		if err != nil {
514 514
 			return nil, err
515 515
 		}
516 516
 		info.Dockerfile = dockerfile
517 517
 	}
518
-
519
-	if info.Dockerfile == nil && len(info.Types) == 0 {
520
-		return nil, ErrNoLanguageDetected
518
+	if _, ok, err := e.JenkinsfileTester.Has(dir); err == nil && ok {
519
+		info.Jenkinsfile = true
521 520
 	}
521
+
522 522
 	return info, nil
523 523
 }
524 524
 
... ...
@@ -528,8 +530,8 @@ func (e SourceRepositoryEnumerator) Detect(dir string, dockerStrategy bool) (*So
528 528
 // more info
529 529
 func StrategyAndSourceForRepository(repo *SourceRepository, image *ImageRef) (*BuildStrategyRef, *SourceRef, error) {
530 530
 	strategy := &BuildStrategyRef{
531
-		Base:          image,
532
-		IsDockerBuild: repo.IsDockerBuild(),
531
+		Base:     image,
532
+		Strategy: repo.strategy,
533 533
 	}
534 534
 	source := &SourceRef{
535 535
 		Binary:       repo.binary,
... ...
@@ -1,6 +1,10 @@
1 1
 package app
2 2
 
3
-import "testing"
3
+import (
4
+	"testing"
5
+
6
+	"github.com/openshift/origin/pkg/generate"
7
+)
4 8
 
5 9
 func TestAddBuildSecrets(t *testing.T) {
6 10
 	type result struct{ name, dest string }
... ...
@@ -35,12 +39,13 @@ func TestAddBuildSecrets(t *testing.T) {
35 35
 		},
36 36
 	}
37 37
 	repo := &SourceRepository{}
38
-	if err := repo.AddBuildSecrets([]string{"secret1:/absolute/path"}, true); err == nil {
38
+	repo.strategy = generate.StrategyDocker
39
+	if err := repo.AddBuildSecrets([]string{"secret1:/absolute/path"}); err == nil {
39 40
 		t.Errorf("expected error for docker strategy when destDir is absolute")
40 41
 	}
41 42
 	for _, item := range table {
42 43
 		repo := &SourceRepository{}
43
-		err := repo.AddBuildSecrets(item.in, false)
44
+		err := repo.AddBuildSecrets(item.in)
44 45
 		if err != nil && len(item.expect) != 0 {
45 46
 			t.Errorf("unexpected error: %v", err)
46 47
 			continue
47 48
deleted file mode 100644
... ...
@@ -1,75 +0,0 @@
1
-package app
2
-
3
-import (
4
-	"io/ioutil"
5
-	"path/filepath"
6
-
7
-	"github.com/openshift/origin/pkg/generate/dockerfile"
8
-	"github.com/openshift/origin/pkg/generate/errors"
9
-	"github.com/openshift/origin/pkg/generate/git"
10
-	"github.com/openshift/origin/pkg/generate/source"
11
-)
12
-
13
-// BuildStrategyRefGenerator generates BuildStrategyRef
14
-//
15
-// Flows for BuildStrategyRef
16
-// SourceRef -> BuildStrategyRef
17
-// SourceRef + Docker Context -> BuildStrategyRef
18
-// Docker Context + Parent Image -> BuildStrategyRef
19
-// STI Builder Image -> BuildStrategyRef
20
-type BuildStrategyRefGenerator struct {
21
-	gitRepository     git.Repository
22
-	dockerfileFinder  dockerfile.Finder
23
-	sourceDetectors   source.Detectors
24
-	imageRefGenerator ImageRefGenerator
25
-}
26
-
27
-// NewBuildStrategyRefGenerator creates a BuildStrategyRefGenerator
28
-func NewBuildStrategyRefGenerator(sourceDetectors source.Detectors) *BuildStrategyRefGenerator {
29
-	return &BuildStrategyRefGenerator{
30
-		gitRepository:     git.NewRepository(),
31
-		dockerfileFinder:  dockerfile.NewFinder(),
32
-		sourceDetectors:   sourceDetectors,
33
-		imageRefGenerator: NewImageRefGenerator(),
34
-	}
35
-}
36
-
37
-// FromDockerContextAndParent generates a build strategy ref from a context path and parent image name
38
-func (g *BuildStrategyRefGenerator) FromDockerContextAndParent(parentRef *ImageRef) (*BuildStrategyRef, error) {
39
-	return &BuildStrategyRef{
40
-		IsDockerBuild: true,
41
-		Base:          parentRef,
42
-	}, nil
43
-}
44
-
45
-// FromSTIBuilderImage generates a build strategy from a builder image ref
46
-func (g *BuildStrategyRefGenerator) FromSTIBuilderImage(image *ImageRef) (*BuildStrategyRef, error) {
47
-	return &BuildStrategyRef{
48
-		IsDockerBuild: false,
49
-		Base:          image,
50
-	}, nil
51
-}
52
-
53
-func (g *BuildStrategyRefGenerator) detectDockerFile(dir string) (contextDir string, found bool, err error) {
54
-	dockerFiles, err := g.dockerfileFinder.Find(dir)
55
-	if err != nil {
56
-		return "", false, err
57
-	}
58
-	if len(dockerFiles) > 1 {
59
-		return "", true, errors.NewMultipleDockerfilesErr(dockerFiles)
60
-	}
61
-	if len(dockerFiles) == 1 {
62
-		return filepath.Dir(dockerFiles[0]), true, nil
63
-	}
64
-	return "", false, nil
65
-}
66
-
67
-func (g *BuildStrategyRefGenerator) getSource(srcRef *SourceRef) error {
68
-	var err error
69
-	// Clone git repository into a local directory
70
-	if srcRef.Dir, err = ioutil.TempDir("", "gen"); err != nil {
71
-		return err
72
-	}
73
-	_, err = CloneAndCheckoutSources(g.gitRepository, srcRef.URL.String(), srcRef.Ref, srcRef.Dir, "")
74
-	return err
75
-}
76 1
deleted file mode 100644
... ...
@@ -1,80 +0,0 @@
1
-package app
2
-
3
-import (
4
-	"testing"
5
-
6
-	"github.com/openshift/origin/pkg/generate/app/test"
7
-	"github.com/openshift/origin/pkg/generate/source"
8
-)
9
-
10
-var sourceDetectors = source.Detectors{
11
-	fakeDetector,
12
-}
13
-
14
-func TestFromSTIBuilderImage(t *testing.T) {
15
-	g := &BuildStrategyRefGenerator{
16
-		gitRepository:     &test.FakeGit{},
17
-		dockerfileFinder:  &fakeFinder{},
18
-		sourceDetectors:   sourceDetectors,
19
-		imageRefGenerator: NewImageRefGenerator(),
20
-	}
21
-	imgRef, err := g.imageRefGenerator.FromName("test/image")
22
-	if err != nil {
23
-		t.Fatalf("Unexpected error generating imageRef: %v", err)
24
-	}
25
-	strategy, err := g.FromSTIBuilderImage(imgRef)
26
-	if err != nil {
27
-		t.Fatalf("Unexpected error: %v", err)
28
-	}
29
-	if strategy.Base != imgRef {
30
-		t.Fatalf("Unexpected image reference: %v", strategy.Base)
31
-	}
32
-	if strategy.IsDockerBuild {
33
-		t.Fatalf("Expected IsDockerBuild to be false")
34
-	}
35
-}
36
-
37
-func TestFromDockerContextAndParent(t *testing.T) {
38
-	g := &BuildStrategyRefGenerator{
39
-		gitRepository:     &test.FakeGit{},
40
-		dockerfileFinder:  &fakeFinder{},
41
-		sourceDetectors:   sourceDetectors,
42
-		imageRefGenerator: NewImageRefGenerator(),
43
-	}
44
-	imgRef, err := g.imageRefGenerator.FromName("test/parentimage")
45
-	if err != nil {
46
-		t.Fatalf("Unexpected error: %v", err)
47
-	}
48
-	strategy, err := g.FromDockerContextAndParent(imgRef)
49
-	if err != nil {
50
-		t.Fatalf("Unexpected error: %v", err)
51
-	}
52
-	if strategy.Base.Reference.Name != "parentimage" {
53
-		t.Fatalf("Unexpected base image: %#v", strategy.Base)
54
-	}
55
-	if !strategy.IsDockerBuild {
56
-		t.Fatalf("Expected IsDockerBuild to be true")
57
-	}
58
-}
59
-
60
-type fakeFinder struct {
61
-	result []string
62
-}
63
-
64
-func (f *fakeFinder) Find(dir string) ([]string, error) {
65
-	return f.result, nil
66
-}
67
-
68
-type dfile map[string][]string
69
-
70
-func (d dfile) GetDirective(name string) ([]string, bool) {
71
-	result, ok := d[name]
72
-	return result, ok
73
-}
74
-
75
-func fakeDetector(dir string) (*source.Info, bool) {
76
-	return &source.Info{
77
-		Platform: "JEE",
78
-		Version:  "1.0",
79
-	}, true
80
-}
... ...
@@ -16,6 +16,7 @@ import (
16 16
 	"k8s.io/kubernetes/pkg/util/sets"
17 17
 
18 18
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
19
+	"github.com/openshift/origin/pkg/generate"
19 20
 	"github.com/openshift/origin/pkg/generate/app"
20 21
 	templateapi "github.com/openshift/origin/pkg/template/api"
21 22
 	"github.com/openshift/origin/pkg/util/docker/dockerfile"
... ...
@@ -178,7 +179,7 @@ func (g *Generator) Generate(body []byte) (*templateapi.Template, error) {
178 178
 		return nil, fmt.Errorf("app.json did not contain a repository URL and no local path was specified")
179 179
 	}
180 180
 
181
-	repo, err := app.NewSourceRepository(buildPath)
181
+	repo, err := app.NewSourceRepository(buildPath, generate.StrategyDocker)
182 182
 	if err != nil {
183 183
 		return nil, err
184 184
 	}
... ...
@@ -207,8 +208,6 @@ func (g *Generator) Generate(body []byte) (*templateapi.Template, error) {
207 207
 	}
208 208
 	// TODO: look for procfile for more info?
209 209
 
210
-	repo.BuildWithDocker()
211
-
212 210
 	image, err := imageGen.FromNameAndPorts(baseImage, ports)
213 211
 	if err != nil {
214 212
 		return nil, err
... ...
@@ -182,7 +182,6 @@ func Generate(paths ...string) (*templateapi.Template, error) {
182 182
 			errs = append(errs, err)
183 183
 			continue
184 184
 		}
185
-		repo.BuildWithDocker()
186 185
 
187 186
 		info := repo.Info()
188 187
 		if info == nil || info.Dockerfile == nil {
... ...
@@ -4,11 +4,9 @@ import (
4 4
 	"os"
5 5
 	"path/filepath"
6 6
 	"strings"
7
-)
8 7
 
9
-type Tester interface {
10
-	Has(dir string) (string, bool, error)
11
-}
8
+	"github.com/openshift/origin/pkg/generate"
9
+)
12 10
 
13 11
 type StatFunc func(path string) (os.FileInfo, error)
14 12
 
... ...
@@ -24,7 +22,7 @@ func (t StatFunc) Has(dir string) (string, bool, error) {
24 24
 	return path, true, nil
25 25
 }
26 26
 
27
-func NewTester() Tester {
27
+func NewTester() generate.Tester {
28 28
 	return StatFunc(os.Stat)
29 29
 }
30 30
 
31 31
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+// Package jenkinsfile provides utilities for finding and parsing Jenkinsfiles
1
+package jenkinsfile
0 2
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+package jenkinsfile
1
+
2
+import (
3
+	"os"
4
+	"path/filepath"
5
+
6
+	"github.com/openshift/origin/pkg/generate"
7
+)
8
+
9
+type tester bool
10
+
11
+func (t tester) Has(dir string) (string, bool, error) {
12
+	path := filepath.Join(dir, "Jenkinsfile")
13
+	_, err := os.Stat(path)
14
+	if os.IsNotExist(err) {
15
+		return "", false, nil
16
+	}
17
+	if err != nil {
18
+		return "", false, err
19
+	}
20
+	return path, true, nil
21
+}
22
+
23
+func NewTester() generate.Tester {
24
+	return tester(true)
25
+}
0 26
new file mode 100644
... ...
@@ -0,0 +1,56 @@
0
+package generate
1
+
2
+import (
3
+	"fmt"
4
+	"strings"
5
+
6
+	"github.com/golang/glog"
7
+)
8
+
9
+type Tester interface {
10
+	Has(dir string) (string, bool, error)
11
+}
12
+
13
+type Strategy int
14
+
15
+const (
16
+	StrategyUnspecified Strategy = iota
17
+	StrategySource
18
+	StrategyDocker
19
+	StrategyPipeline
20
+)
21
+
22
+func (s Strategy) String() string {
23
+	switch s {
24
+	case StrategyUnspecified:
25
+		return ""
26
+	case StrategySource:
27
+		return "source"
28
+	case StrategyDocker:
29
+		return "Docker"
30
+	case StrategyPipeline:
31
+		return "pipeline"
32
+	}
33
+	glog.Error("unknown strategy")
34
+	return ""
35
+}
36
+
37
+func (s Strategy) Type() string {
38
+	return "strategy"
39
+}
40
+
41
+func (s *Strategy) Set(str string) error {
42
+	switch strings.ToLower(str) {
43
+	case "":
44
+		*s = StrategyUnspecified
45
+	case "docker":
46
+		*s = StrategyDocker
47
+	case "pipeline":
48
+		*s = StrategyPipeline
49
+	case "source":
50
+		*s = StrategySource
51
+	default:
52
+		return fmt.Errorf("invalid strategy: %s. Must be 'docker', 'pipeline' or 'source'.", str)
53
+	}
54
+	return nil
55
+}
... ...
@@ -33,11 +33,13 @@ import (
33 33
 	client "github.com/openshift/origin/pkg/client/testclient"
34 34
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
35 35
 	"github.com/openshift/origin/pkg/dockerregistry"
36
+	"github.com/openshift/origin/pkg/generate"
36 37
 	"github.com/openshift/origin/pkg/generate/app"
37 38
 	"github.com/openshift/origin/pkg/generate/app/cmd"
38 39
 	apptest "github.com/openshift/origin/pkg/generate/app/test"
39 40
 	"github.com/openshift/origin/pkg/generate/dockerfile"
40 41
 	"github.com/openshift/origin/pkg/generate/git"
42
+	"github.com/openshift/origin/pkg/generate/jenkinsfile"
41 43
 	"github.com/openshift/origin/pkg/generate/source"
42 44
 	imageapi "github.com/openshift/origin/pkg/image/api"
43 45
 	templateapi "github.com/openshift/origin/pkg/template/api"
... ...
@@ -165,7 +167,7 @@ func TestNewAppResolve(t *testing.T) {
165 165
 			name: "Successful docker build",
166 166
 			cfg: cmd.AppConfig{
167 167
 				GenerationInputs: cmd.GenerationInputs{
168
-					Strategy: "docker",
168
+					Strategy: generate.StrategyDocker,
169 169
 				},
170 170
 			},
171 171
 			components: app.ComponentReferences{
... ...
@@ -210,8 +212,9 @@ func TestNewAppDetectSource(t *testing.T) {
210 210
 			cfg: &cmd.AppConfig{
211 211
 				Resolvers: cmd.Resolvers{
212 212
 					Detector: app.SourceRepositoryEnumerator{
213
-						Detectors: source.DefaultDetectors,
214
-						Tester:    dockerfile.NewTester(),
213
+						Detectors:         source.DefaultDetectors,
214
+						DockerfileTester:  dockerfile.NewTester(),
215
+						JenkinsfileTester: jenkinsfile.NewTester(),
215 216
 					},
216 217
 					DockerSearcher: dockerSearcher,
217 218
 				},
... ...
@@ -334,12 +337,13 @@ func TestNewAppRunAll(t *testing.T) {
334 334
 						Namespaces:        []string{"default"},
335 335
 					},
336 336
 					Detector: app.SourceRepositoryEnumerator{
337
-						Detectors: source.DefaultDetectors,
338
-						Tester:    dockerfile.NewTester(),
337
+						Detectors:         source.DefaultDetectors,
338
+						DockerfileTester:  dockerfile.NewTester(),
339
+						JenkinsfileTester: jenkinsfile.NewTester(),
339 340
 					},
340 341
 				},
341 342
 				GenerationInputs: cmd.GenerationInputs{
342
-					Strategy: "source",
343
+					Strategy: generate.StrategySource,
343 344
 				},
344 345
 				Typer:           kapi.Scheme,
345 346
 				OSClient:        &client.Fake{},
... ...
@@ -376,13 +380,14 @@ func TestNewAppRunAll(t *testing.T) {
376 376
 						Namespaces:                []string{"openshift", "default"},
377 377
 					},
378 378
 					Detector: app.SourceRepositoryEnumerator{
379
-						Detectors: source.DefaultDetectors,
380
-						Tester:    dockerfile.NewTester(),
379
+						Detectors:         source.DefaultDetectors,
380
+						DockerfileTester:  dockerfile.NewTester(),
381
+						JenkinsfileTester: jenkinsfile.NewTester(),
381 382
 					},
382 383
 				},
383 384
 
384 385
 				GenerationInputs: cmd.GenerationInputs{
385
-					Strategy: "source",
386
+					Strategy: generate.StrategySource,
386 387
 					Labels:   map[string]string{"label1": "value1", "label2": "value2"},
387 388
 				},
388 389
 				Typer:           kapi.Scheme,
... ...
@@ -420,12 +425,13 @@ func TestNewAppRunAll(t *testing.T) {
420 420
 						Namespaces:                []string{"openshift", "default"},
421 421
 					},
422 422
 					Detector: app.SourceRepositoryEnumerator{
423
-						Detectors: source.DefaultDetectors,
424
-						Tester:    dockerfile.NewTester(),
423
+						Detectors:         source.DefaultDetectors,
424
+						DockerfileTester:  dockerfile.NewTester(),
425
+						JenkinsfileTester: jenkinsfile.NewTester(),
425 426
 					},
426 427
 				},
427 428
 				GenerationInputs: cmd.GenerationInputs{
428
-					Strategy: "docker",
429
+					Strategy: generate.StrategyDocker,
429 430
 				},
430 431
 				Typer:           kapi.Scheme,
431 432
 				OSClient:        &client.Fake{},
... ...
@@ -461,8 +467,9 @@ func TestNewAppRunAll(t *testing.T) {
461 461
 						Namespaces:                []string{"openshift", "default"},
462 462
 					},
463 463
 					Detector: app.SourceRepositoryEnumerator{
464
-						Detectors: source.DefaultDetectors,
465
-						Tester:    dockerfile.NewTester(),
464
+						Detectors:         source.DefaultDetectors,
465
+						DockerfileTester:  dockerfile.NewTester(),
466
+						JenkinsfileTester: jenkinsfile.NewTester(),
466 467
 					},
467 468
 				},
468 469
 
... ...
@@ -488,7 +495,7 @@ func TestNewAppRunAll(t *testing.T) {
488 488
 					SourceRepositories: []string{"https://github.com/openshift/ruby-hello-world"},
489 489
 				},
490 490
 				GenerationInputs: cmd.GenerationInputs{
491
-					Strategy:         "source",
491
+					Strategy:         generate.StrategySource,
492 492
 					InsecureRegistry: true,
493 493
 				},
494 494
 
... ...
@@ -513,8 +520,9 @@ func TestNewAppRunAll(t *testing.T) {
513 513
 					},
514 514
 					TemplateFileSearcher: &app.TemplateFileSearcher{},
515 515
 					Detector: app.SourceRepositoryEnumerator{
516
-						Detectors: source.DefaultDetectors,
517
-						Tester:    dockerfile.NewTester(),
516
+						Detectors:         source.DefaultDetectors,
517
+						DockerfileTester:  dockerfile.NewTester(),
518
+						JenkinsfileTester: jenkinsfile.NewTester(),
518 519
 					},
519 520
 				},
520 521
 				Typer:           kapi.Scheme,
... ...
@@ -552,8 +560,9 @@ func TestNewAppRunAll(t *testing.T) {
552 552
 						Namespaces:                []string{"openshift", "default"},
553 553
 					},
554 554
 					Detector: app.SourceRepositoryEnumerator{
555
-						Detectors: source.DefaultDetectors,
556
-						Tester:    dockerfile.NewTester(),
555
+						Detectors:         source.DefaultDetectors,
556
+						DockerfileTester:  dockerfile.NewTester(),
557
+						JenkinsfileTester: jenkinsfile.NewTester(),
557 558
 					},
558 559
 				},
559 560
 
... ...
@@ -602,8 +611,9 @@ func TestNewAppRunAll(t *testing.T) {
602 602
 						Namespaces:                []string{"openshift", "default"},
603 603
 					},
604 604
 					Detector: app.SourceRepositoryEnumerator{
605
-						Detectors: source.DefaultDetectors,
606
-						Tester:    dockerfile.NewTester(),
605
+						Detectors:         source.DefaultDetectors,
606
+						DockerfileTester:  dockerfile.NewTester(),
607
+						JenkinsfileTester: jenkinsfile.NewTester(),
607 608
 					},
608 609
 				},
609 610
 				Typer:           kapi.Scheme,
... ...
@@ -646,8 +656,9 @@ func TestNewAppRunAll(t *testing.T) {
646 646
 						Namespaces:                []string{"openshift", "default"},
647 647
 					},
648 648
 					Detector: app.SourceRepositoryEnumerator{
649
-						Detectors: source.DefaultDetectors,
650
-						Tester:    dockerfile.NewTester(),
649
+						Detectors:         source.DefaultDetectors,
650
+						DockerfileTester:  dockerfile.NewTester(),
651
+						JenkinsfileTester: jenkinsfile.NewTester(),
651 652
 					},
652 653
 				},
653 654
 				Typer:           kapi.Scheme,
... ...
@@ -1063,7 +1074,7 @@ func TestNewAppRunBuilds(t *testing.T) {
1063 1063
 			config: &cmd.AppConfig{
1064 1064
 				GenerationInputs: cmd.GenerationInputs{
1065 1065
 					Dockerfile: "FROM openshift/origin-base\nUSER foo",
1066
-					Strategy:   "source",
1066
+					Strategy:   generate.StrategySource,
1067 1067
 				},
1068 1068
 			},
1069 1069
 			expectedErr: func(err error) bool {
... ...
@@ -1075,7 +1086,7 @@ func TestNewAppRunBuilds(t *testing.T) {
1075 1075
 			config: &cmd.AppConfig{
1076 1076
 				GenerationInputs: cmd.GenerationInputs{
1077 1077
 					Dockerfile: "USER foo",
1078
-					Strategy:   "docker",
1078
+					Strategy:   generate.StrategyDocker,
1079 1079
 				},
1080 1080
 			},
1081 1081
 			expectedErr: func(err error) bool {
... ...
@@ -1216,6 +1227,135 @@ func TestNewAppRunBuilds(t *testing.T) {
1216 1216
 				return nil
1217 1217
 			},
1218 1218
 		},
1219
+		{
1220
+			name: "successful build from source with autodetected jenkinsfile",
1221
+			config: &cmd.AppConfig{
1222
+				ComponentInputs: cmd.ComponentInputs{
1223
+					SourceRepositories: []string{
1224
+						"https://github.com/openshift/nodejs-ex",
1225
+					},
1226
+				},
1227
+				GenerationInputs: cmd.GenerationInputs{
1228
+					ContextDir: "openshift/pipeline",
1229
+				},
1230
+			},
1231
+			expected: map[string][]string{
1232
+				"buildConfig": {"nodejs-ex"},
1233
+			},
1234
+			checkResult: func(res *cmd.AppResult) error {
1235
+				if len(res.List.Items) != 1 {
1236
+					return fmt.Errorf("expected one Item returned")
1237
+				}
1238
+				bc, ok := res.List.Items[0].(*buildapi.BuildConfig)
1239
+				if !ok {
1240
+					return fmt.Errorf("expected Item of type *buildapi.BuildConfig")
1241
+				}
1242
+				if !reflect.DeepEqual(bc.Spec.Output, buildapi.BuildOutput{}) {
1243
+					return fmt.Errorf("invalid bc.Spec.Output, got %#v", bc.Spec.Output)
1244
+				}
1245
+				if !reflect.DeepEqual(bc.Spec.Source, buildapi.BuildSource{
1246
+					ContextDir: "openshift/pipeline",
1247
+					Git:        &buildapi.GitBuildSource{URI: "https://github.com/openshift/nodejs-ex"},
1248
+					Secrets:    []buildapi.SecretBuildSource{},
1249
+				}) {
1250
+					return fmt.Errorf("invalid bc.Spec.Source, got %#v", bc.Spec.Source)
1251
+				}
1252
+				if !reflect.DeepEqual(bc.Spec.Strategy, buildapi.BuildStrategy{JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{}}) {
1253
+					return fmt.Errorf("invalid bc.Spec.Strategy, got %#v", bc.Spec.Strategy)
1254
+				}
1255
+				return nil
1256
+			},
1257
+		},
1258
+		{
1259
+			name: "successful build from component with source with pipeline strategy",
1260
+			config: &cmd.AppConfig{
1261
+				ComponentInputs: cmd.ComponentInputs{
1262
+					Components: []string{
1263
+						"centos/nodejs-4-centos7~https://github.com/openshift/nodejs-ex",
1264
+					},
1265
+				},
1266
+				GenerationInputs: cmd.GenerationInputs{
1267
+					ContextDir: "openshift/pipeline",
1268
+					Strategy:   generate.StrategyPipeline,
1269
+				},
1270
+			},
1271
+			expected: map[string][]string{
1272
+				"buildConfig": {"nodejs-ex"},
1273
+			},
1274
+			checkResult: func(res *cmd.AppResult) error {
1275
+				if len(res.List.Items) != 1 {
1276
+					return fmt.Errorf("expected one Item returned")
1277
+				}
1278
+				bc, ok := res.List.Items[0].(*buildapi.BuildConfig)
1279
+				if !ok {
1280
+					return fmt.Errorf("expected Item of type *buildapi.BuildConfig")
1281
+				}
1282
+				if !reflect.DeepEqual(bc.Spec.Output, buildapi.BuildOutput{}) {
1283
+					return fmt.Errorf("invalid bc.Spec.Output, got %#v", bc.Spec.Output)
1284
+				}
1285
+				if !reflect.DeepEqual(bc.Spec.Source, buildapi.BuildSource{
1286
+					ContextDir: "openshift/pipeline",
1287
+					Git:        &buildapi.GitBuildSource{URI: "https://github.com/openshift/nodejs-ex"},
1288
+					Secrets:    []buildapi.SecretBuildSource{},
1289
+				}) {
1290
+					return fmt.Errorf("invalid bc.Spec.Source, got %#v", bc.Spec.Source.Git)
1291
+				}
1292
+				if !reflect.DeepEqual(bc.Spec.Strategy, buildapi.BuildStrategy{JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{}}) {
1293
+					return fmt.Errorf("invalid bc.Spec.Strategy, got %#v", bc.Spec.Strategy)
1294
+				}
1295
+				return nil
1296
+			},
1297
+		},
1298
+		{
1299
+			name: "successful build from source with jenkinsfile with pipeline strategy",
1300
+			config: &cmd.AppConfig{
1301
+				ComponentInputs: cmd.ComponentInputs{
1302
+					SourceRepositories: []string{
1303
+						"https://github.com/openshift/nodejs-ex",
1304
+					},
1305
+				},
1306
+				GenerationInputs: cmd.GenerationInputs{
1307
+					ContextDir: "openshift/pipeline",
1308
+					Strategy:   generate.StrategyPipeline,
1309
+				},
1310
+			},
1311
+			expected: map[string][]string{
1312
+				"buildConfig": {"nodejs-ex"},
1313
+			},
1314
+		},
1315
+		{
1316
+			name: "failed build from source with jenkinsfile with docker strategy",
1317
+			config: &cmd.AppConfig{
1318
+				ComponentInputs: cmd.ComponentInputs{
1319
+					SourceRepositories: []string{
1320
+						"https://github.com/openshift/nodejs-ex",
1321
+					},
1322
+				},
1323
+				GenerationInputs: cmd.GenerationInputs{
1324
+					ContextDir: "openshift/pipeline",
1325
+					Strategy:   generate.StrategyDocker,
1326
+				},
1327
+			},
1328
+			expectedErr: func(err error) bool {
1329
+				return strings.HasPrefix(err.Error(), "No Dockerfile was found in the repository")
1330
+			},
1331
+		},
1332
+		{
1333
+			name: "failed build from source without jenkinsfile with pipeline strategy",
1334
+			config: &cmd.AppConfig{
1335
+				ComponentInputs: cmd.ComponentInputs{
1336
+					SourceRepositories: []string{
1337
+						"https://github.com/openshift/nodejs-ex",
1338
+					},
1339
+				},
1340
+				GenerationInputs: cmd.GenerationInputs{
1341
+					Strategy: generate.StrategyPipeline,
1342
+				},
1343
+			},
1344
+			expectedErr: func(err error) bool {
1345
+				return strings.HasPrefix(err.Error(), "No Jenkinsfile was found in the repository")
1346
+			},
1347
+		},
1219 1348
 	}
1220 1349
 	for _, test := range tests {
1221 1350
 		stdout, stderr := PrepareAppConfig(test.config)
... ...
@@ -1526,8 +1666,9 @@ func TestNewAppNewBuildEnvVars(t *testing.T) {
1526 1526
 				Resolvers: cmd.Resolvers{
1527 1527
 					DockerSearcher: dockerSearcher,
1528 1528
 					Detector: app.SourceRepositoryEnumerator{
1529
-						Detectors: source.DefaultDetectors,
1530
-						Tester:    dockerfile.NewTester(),
1529
+						Detectors:         source.DefaultDetectors,
1530
+						DockerfileTester:  dockerfile.NewTester(),
1531
+						JenkinsfileTester: jenkinsfile.NewTester(),
1531 1532
 					},
1532 1533
 				},
1533 1534
 				Typer:           kapi.Scheme,
... ...
@@ -1595,8 +1736,9 @@ func TestNewAppBuildConfigEnvVarsAndSecrets(t *testing.T) {
1595 1595
 				Resolvers: cmd.Resolvers{
1596 1596
 					DockerSearcher: dockerSearcher,
1597 1597
 					Detector: app.SourceRepositoryEnumerator{
1598
-						Detectors: source.DefaultDetectors,
1599
-						Tester:    dockerfile.NewTester(),
1598
+						Detectors:         source.DefaultDetectors,
1599
+						DockerfileTester:  dockerfile.NewTester(),
1600
+						JenkinsfileTester: jenkinsfile.NewTester(),
1600 1601
 					},
1601 1602
 				},
1602 1603
 				Typer:           kapi.Scheme,
... ...
@@ -1686,14 +1828,15 @@ func TestNewAppSourceAuthRequired(t *testing.T) {
1686 1686
 	for _, test := range tests {
1687 1687
 		url := setupLocalGitRepo(t, test.passwordProtected, test.useProxy)
1688 1688
 
1689
-		sourceRepo, err := app.NewSourceRepository(url)
1689
+		sourceRepo, err := app.NewSourceRepository(url, generate.StrategySource)
1690 1690
 		if err != nil {
1691 1691
 			t.Fatalf("%v", err)
1692 1692
 		}
1693 1693
 
1694 1694
 		detector := app.SourceRepositoryEnumerator{
1695
-			Detectors: source.DefaultDetectors,
1696
-			Tester:    dockerfile.NewTester(),
1695
+			Detectors:         source.DefaultDetectors,
1696
+			DockerfileTester:  dockerfile.NewTester(),
1697
+			JenkinsfileTester: jenkinsfile.NewTester(),
1697 1698
 		}
1698 1699
 
1699 1700
 		if err = sourceRepo.Detect(detector, true); err != nil {
... ...
@@ -1797,7 +1940,7 @@ name = developer
1797 1797
 email = developer@org.org
1798 1798
 `
1799 1799
 	if passwordProtected {
1800
-		authSection := `	
1800
+		authSection := `
1801 1801
 [url %q]
1802 1802
 insteadOf = %s
1803 1803
 		`
... ...
@@ -1968,7 +2111,7 @@ func MockSourceRepositories(t *testing.T, file string) []*app.SourceRepository {
1968 1968
 		"https://github.com/openshift/ruby-hello-world.git",
1969 1969
 		file,
1970 1970
 	} {
1971
-		s, err := app.NewSourceRepository(location)
1971
+		s, err := app.NewSourceRepository(location, generate.StrategySource)
1972 1972
 		if err != nil {
1973 1973
 			t.Fatal(err)
1974 1974
 		}
... ...
@@ -1985,8 +2128,9 @@ func PrepareAppConfig(config *cmd.AppConfig) (stdout, stderr *bytes.Buffer) {
1985 1985
 	config.Out, config.ErrOut = stdout, stderr
1986 1986
 
1987 1987
 	config.Detector = app.SourceRepositoryEnumerator{
1988
-		Detectors: source.DefaultDetectors,
1989
-		Tester:    dockerfile.NewTester(),
1988
+		Detectors:         source.DefaultDetectors,
1989
+		DockerfileTester:  dockerfile.NewTester(),
1990
+		JenkinsfileTester: jenkinsfile.NewTester(),
1990 1991
 	}
1991 1992
 	if config.DockerSearcher == nil {
1992 1993
 		config.DockerSearcher = app.DockerRegistrySearcher{