func TestBuildTemplates(t *testing.T) { tests := map[string]struct { templateName string namespace string parms map[string]string }{ "simple": { templateName: "first-stored-template", namespace: "default", parms: map[string]string{}, }, } for n, c := range tests { appCfg := AppConfig{} appCfg.Out = &bytes.Buffer{} appCfg.refBuilder = &app.ReferenceBuilder{} appCfg.SetOpenShiftClient(&client.Fake{}, c.namespace) appCfg.KubeClient = ktestclient.NewSimpleFake() appCfg.templateSearcher = fakeTemplateSearcher() appCfg.AddArguments([]string{c.templateName}) appCfg.TemplateParameters = []string{} for k, v := range c.parms { appCfg.TemplateParameters = append(appCfg.TemplateParameters, fmt.Sprintf("%v=%v", k, v)) } components, _, _, parms, err := appCfg.validate() if err != nil { t.Errorf("%s: Unexpected error: %v", n, err) } err = appCfg.resolve(components) if err != nil { t.Errorf("%s: Unexpected error: %v", n, err) } _, err = appCfg.buildTemplates(components, app.Environment(parms)) if err != nil { t.Errorf("%s: Unexpected error: %v", n, err) } for _, component := range components { match := component.Input().ResolvedMatch if !match.IsTemplate() { t.Errorf("%s: Expected template match, got: %v", n, match) } if c.templateName != match.Name { t.Errorf("%s: Expected template name %q, got: %q", n, c.templateName, match.Name) } if len(parms) != len(c.parms) { t.Errorf("%s: Template parameters don't match. Expected: %v, Got: %v", n, c.parms, parms) } for p, v := range parms { if c.parms[p] != v { t.Errorf("%s: Template parameters don't match. Expected: %v, Got: %v", n, c.parms, parms) break } } } } }
// run executes the provided config applying provided acceptors. func (c *AppConfig) run(out, errOut io.Writer, acceptors app.Acceptors) (*AppResult, error) { c.ensureDockerSearcher() repositories, err := c.individualSourceRepositories() if err != nil { return nil, err } err = c.detectSource(repositories) if err != nil { return nil, err } components, repositories, environment, parameters, err := c.validate() if err != nil { return nil, err } if err := c.resolve(components); err != nil { return nil, err } // Couple source with resolved builder components if possible if err := c.ensureHasSource(components.NeedsSource(), repositories.NotUsed()); err != nil { return nil, err } // For source repos that are not yet coupled with a component, create components sourceComponents, err := c.componentsForRepos(repositories.NotUsed()) if err != nil { return nil, err } // resolve the source repo components if err := c.resolve(sourceComponents); err != nil { return nil, err } components = append(components, sourceComponents...) glog.V(4).Infof("Code %v", repositories) glog.V(4).Infof("Components %v", components) if len(repositories) == 0 && len(components) == 0 { return nil, ErrNoInputs } if len(c.Name) > 0 { if err := c.validateEnforcedName(); err != nil { return nil, err } } if len(components.ImageComponentRefs()) > 1 && len(c.Name) > 0 { return nil, fmt.Errorf("only one component or source repository can be used when specifying a name") } pipelines, err := c.buildPipelines(components.ImageComponentRefs(), app.Environment(environment)) if err != nil { return nil, err } objects := app.Objects{} accept := app.NewAcceptFirst() warned := make(map[string]struct{}) for _, p := range pipelines { accepted, err := p.Objects(accept, acceptors) if err != nil { return nil, fmt.Errorf("can't setup %q: %v", p.From, err) } if p.Image != nil && p.Image.HasEmptyDir { if _, ok := warned[p.Image.Name]; !ok { fmt.Fprintf(errOut, "NOTICE: Image %q uses an EmptyDir volume. Data in EmptyDir volumes is not persisted across deployments.\n", p.Image.Name) warned[p.Image.Name] = struct{}{} } } objects = append(objects, accepted...) } objects = app.AddServices(objects, false) templateObjects, err := c.buildTemplates(components.TemplateComponentRefs(), app.Environment(parameters)) if err != nil { return nil, err } objects = append(objects, templateObjects...) buildNames := []string{} for _, obj := range objects { switch t := obj.(type) { case *buildapi.BuildConfig: buildNames = append(buildNames, t.Name) } } name := c.Name if len(name) == 0 { for _, pipeline := range pipelines { if pipeline.Deployment != nil { name = pipeline.Deployment.Name break } } } return &AppResult{ List: &kapi.List{Items: objects}, Name: name, BuildNames: buildNames, HasSource: len(repositories) != 0, Namespace: c.originNamespace, }, nil }
// run executes the provided config applying provided acceptors. func (c *AppConfig) run(acceptors app.Acceptors) (*AppResult, error) { c.ensureDockerSearcher() repositories, err := c.individualSourceRepositories() if err != nil { return nil, err } err = c.detectSource(repositories) if err != nil { return nil, err } components, repositories, environment, parameters, err := c.validate() if err != nil { return nil, err } if err := c.resolve(components); err != nil { return nil, err } components, err = c.inferBuildTypes(components) if err != nil { return nil, err } // Couple source with resolved builder components if possible if err := c.ensureHasSource(components.NeedsSource(), repositories.NotUsed()); err != nil { return nil, err } // For source repos that are not yet coupled with a component, create components sourceComponents, err := c.componentsForRepos(repositories.NotUsed()) if err != nil { return nil, err } // resolve the source repo components if err := c.resolve(sourceComponents); err != nil { return nil, err } components = append(components, sourceComponents...) glog.V(4).Infof("Code [%v]", repositories) glog.V(4).Infof("Components [%v]", components) if len(repositories) == 0 && len(components) == 0 { return nil, ErrNoInputs } if len(c.Name) > 0 { if err := validateEnforcedName(c.Name); err != nil { return nil, err } } if len(c.To) > 0 { if err := validateOutputImageReference(c.To); err != nil { return nil, err } } imageRefs := components.ImageComponentRefs() if len(imageRefs) > 1 && len(c.Name) > 0 { return nil, fmt.Errorf("only one component or source repository can be used when specifying a name") } if len(imageRefs) > 1 && len(c.To) > 0 { return nil, fmt.Errorf("only one component or source repository can be used when specifying an output image reference") } env := app.Environment(environment) // identify if there are installable components in the input provided by the user installables, name, err := c.installComponents(components, env) if err != nil { return nil, err } if len(installables) > 0 { return &AppResult{ List: &kapi.List{Items: installables}, Name: name, Namespace: c.originNamespace, GeneratedJobs: true, }, nil } pipelines, err := c.buildPipelines(imageRefs, env) if err != nil { if err == app.ErrNameRequired { return nil, fmt.Errorf("can't suggest a valid name, please specify a name with --name") } if err, ok := err.(app.CircularOutputReferenceError); ok { return nil, fmt.Errorf("%v, please specify a different output reference with --to", err) } return nil, err } objects := app.Objects{} accept := app.NewAcceptFirst() for _, p := range pipelines { accepted, err := p.Objects(accept, acceptors) if err != nil { return nil, fmt.Errorf("can't setup %q: %v", p.From, err) } objects = append(objects, accepted...) } objects = app.AddServices(objects, false) templateObjects, err := c.buildTemplates(components.TemplateComponentRefs(), app.Environment(parameters)) if err != nil { return nil, err } objects = append(objects, templateObjects...) name = c.Name if len(name) == 0 { for _, pipeline := range pipelines { if pipeline.Deployment != nil { name = pipeline.Deployment.Name break } } } if len(name) == 0 { for _, obj := range objects { if bc, ok := obj.(*buildapi.BuildConfig); ok { name = bc.Name break } } } return &AppResult{ List: &kapi.List{Items: objects}, Name: name, HasSource: len(repositories) != 0, Namespace: c.originNamespace, }, nil }
// Run executes the provided config to generate objects. func (c *AppConfig) Run() (*AppResult, error) { environment, parameters, err := c.validate() if err != nil { return nil, err } // TODO: I don't belong here c.ensureDockerSearch() resolved, err := Resolve(&c.Resolvers, &c.ComponentInputs, &c.GenerationInputs) if err != nil { return nil, err } repositories := resolved.Repositories components := resolved.Components if err := c.validateBuilders(components); err != nil { return nil, err } if len(repositories) == 0 && len(components) == 0 { return nil, ErrNoInputs } if len(c.Name) > 0 { if err := validateEnforcedName(c.Name); err != nil { return nil, err } } if err := optionallyValidateExposedPorts(c, repositories); err != nil { return nil, err } if len(c.To) > 0 { if err := validateOutputImageReference(c.To); err != nil { return nil, err } } if len(components.ImageComponentRefs().Group()) > 1 && len(c.Name) > 0 { return nil, errors.New("only one component or source repository can be used when specifying a name") } if len(components.UseSource()) > 1 && len(c.To) > 0 { return nil, errors.New("only one component with source can be used when specifying an output image reference") } env := app.Environment(environment) // identify if there are installable components in the input provided by the user installables, name, err := c.installComponents(components, env) if err != nil { return nil, err } if len(installables) > 0 { return &AppResult{ List: &kapi.List{Items: installables}, Name: name, Namespace: c.OriginNamespace, GeneratedJobs: true, }, nil } pipelines, err := c.buildPipelines(components.ImageComponentRefs(), env) if err != nil { if err == app.ErrNameRequired { return nil, errors.New("can't suggest a valid name, please specify a name with --name") } return nil, err } acceptors := app.Acceptors{app.NewAcceptUnique(c.Typer), app.AcceptNew} objects := app.Objects{} accept := app.NewAcceptFirst() for _, p := range pipelines { accepted, err := p.Objects(accept, acceptors) if err != nil { return nil, fmt.Errorf("can't setup %q: %v", p.From, err) } objects = append(objects, accepted...) } objects = app.AddServices(objects, false) templateName, templateObjects, err := c.buildTemplates(components.TemplateComponentRefs(), app.Environment(parameters)) if err != nil { return nil, err } objects = append(objects, templateObjects...) name = c.Name if len(name) == 0 { name = templateName } if len(name) == 0 { for _, pipeline := range pipelines { if pipeline.Deployment != nil { name = pipeline.Deployment.Name break } } } if len(name) == 0 { for _, obj := range objects { if bc, ok := obj.(*buildapi.BuildConfig); ok { name = bc.Name break } } } // Only check circular references for `oc new-build`. if c.ExpectToBuild { err = c.checkCircularReferences(objects) if err != nil { if err, ok := err.(app.CircularOutputReferenceError); ok { if len(c.To) == 0 { // Output reference was generated, return error. return nil, fmt.Errorf("%v, set a different tag with --to", err) } // Output reference was explicitly provided, print warning. fmt.Fprintf(c.ErrOut, "--> WARNING: %v\n", err) } else { return nil, err } } } return &AppResult{ List: &kapi.List{Items: objects}, Name: name, HasSource: len(repositories) != 0, Namespace: c.OriginNamespace, }, nil }
// run executes the provided config applying provided acceptors. func (c *AppConfig) run(acceptors app.Acceptors) (*AppResult, error) { c.ensureDockerSearcher() repositories, err := c.individualSourceRepositories() if err != nil { return nil, err } err = c.detectSource(repositories) if err != nil { return nil, err } components, repositories, environment, parameters, err := c.validate() if err != nil { return nil, err } if err := c.resolve(components); err != nil { return nil, err } if err := c.inferBuildTypes(components); err != nil { return nil, err } // Couple source with resolved builder components if possible if err := c.ensureHasSource(components.NeedsSource(), repositories.NotUsed()); err != nil { return nil, err } // For source repos that are not yet coupled with a component, create components sourceComponents, err := c.componentsForRepos(repositories.NotUsed()) if err != nil { return nil, err } // resolve the source repo components if err := c.resolve(sourceComponents); err != nil { return nil, err } components = append(components, sourceComponents...) glog.V(4).Infof("Code [%v]", repositories) glog.V(4).Infof("Components [%v]", components) if len(repositories) == 0 && len(components) == 0 { return nil, ErrNoInputs } if len(c.Name) > 0 { if err := c.validateEnforcedName(); err != nil { return nil, err } } imageRefs := components.ImageComponentRefs() if len(imageRefs) > 1 && len(c.Name) > 0 { return nil, fmt.Errorf("only one component or source repository can be used when specifying a name") } // identify if there are installable components in the input provided by the user installables, name, err := c.installComponents(components) if err != nil { return nil, err } if len(installables) > 0 { return &AppResult{ List: &kapi.List{Items: installables}, Name: name, Namespace: c.originNamespace, GeneratedJobs: true, }, nil } pipelines, err := c.buildPipelines(imageRefs, app.Environment(environment)) if err != nil { return nil, err } objects := app.Objects{} accept := app.NewAcceptFirst() warned := make(map[string]struct{}) for _, p := range pipelines { accepted, err := p.Objects(accept, acceptors) if err != nil { return nil, fmt.Errorf("can't setup %q: %v", p.From, err) } if p.Image != nil && p.Image.HasEmptyDir { spec := p.Image.PullSpec() if _, ok := warned[spec]; ok { fmt.Fprintf(c.ErrOut, "WARNING: Image %q uses an empty directory volume. Data in these volumes is not persisted across deployments.\n", p.Image.Reference.Name) warned[spec] = struct{}{} } } objects = append(objects, accepted...) } objects = app.AddServices(objects, false) templateObjects, err := c.buildTemplates(components.TemplateComponentRefs(), app.Environment(parameters)) if err != nil { return nil, err } objects = append(objects, templateObjects...) name = c.Name if len(name) == 0 { for _, pipeline := range pipelines { if pipeline.Deployment != nil { name = pipeline.Deployment.Name break } } } return &AppResult{ List: &kapi.List{Items: objects}, Name: name, HasSource: len(repositories) != 0, Namespace: c.originNamespace, }, nil }
// run executes the provided config applying provided acceptors. func (c *AppConfig) run(out io.Writer, acceptors app.Acceptors) (*AppResult, error) { c.ensureDockerResolver() repositories, err := c.individualSourceRepositories() if err != nil { return nil, err } err = c.detectSource(repositories) if err != nil { return nil, err } components, repositories, environment, parameters, err := c.validate() if err != nil { return nil, err } if err := c.resolve(components); err != nil { return nil, err } // Couple source with resolved builder components if possible if err := c.ensureHasSource(components.NeedsSource(), repositories.NotUsed()); err != nil { return nil, err } // For source repos that are not yet coupled with a component, create components sourceComponents, err := c.componentsForRepos(repositories.NotUsed()) if err != nil { return nil, err } // resolve the source repo components if err := c.resolve(sourceComponents); err != nil { return nil, err } components = append(components, sourceComponents...) glog.V(4).Infof("Code %v", repositories) glog.V(4).Infof("Components %v", components) if len(repositories) == 0 && len(components) == 0 { return nil, ErrNoInputs } pipelines, err := c.buildPipelines(components, app.Environment(environment)) if err != nil { return nil, err } objects := app.Objects{} accept := app.NewAcceptFirst() for _, p := range pipelines { accepted, err := p.Objects(accept, acceptors) if err != nil { return nil, fmt.Errorf("can't setup %q: %v", p.From, err) } objects = append(objects, accepted...) } objects = app.AddServices(objects) templateObjects, err := c.buildTemplates(components, app.Environment(parameters)) if err != nil { return nil, err } objects = append(objects, templateObjects...) buildNames := []string{} for _, obj := range objects { switch t := obj.(type) { case *buildapi.BuildConfig: buildNames = append(buildNames, t.Name) } } return &AppResult{ List: &kapi.List{Items: objects}, BuildNames: buildNames, HasSource: len(repositories) != 0, Namespace: c.originNamespace, }, nil }