1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-10-30 23:57:50 +02:00

feat(cnbBuild) containerImageName will be defaulted if possible (#3437)

Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
Co-authored-by: Johannes Dillmann <j.dillmann@sap.com>
Co-authored-by: Sumit Kulhadia <sumit.kulhadia@sap.com>
This commit is contained in:
Ralf Pannemans
2022-01-14 16:49:45 +01:00
committed by GitHub
parent 4acee9fc85
commit c97625e840
9 changed files with 273 additions and 66 deletions

View File

@@ -6,7 +6,6 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"strings"
"github.com/SAP/jenkins-library/pkg/certutils"
@@ -268,6 +267,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u
return errors.Wrap(err, "failed to check if project descriptor exists")
}
var projectID string
if projDescExists {
descriptor, err := project.ParseDescriptor(config.ProjectDescriptor, utils, httpClient)
if err != nil {
@@ -288,8 +288,19 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u
if descriptor.Include != nil {
include = descriptor.Include
}
projectID = descriptor.ProjectID
}
targetImage, err := cnbutils.GetTargetImage(config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag, projectID, GeneralConfig.EnvRootPath)
if err != nil {
log.SetErrorCategory(log.ErrorConfiguration)
return errors.Wrap(err, "failed to retrieve target image configuration")
}
commonPipelineEnvironment.container.registryURL = fmt.Sprintf("%s://%s", targetImage.ContainerRegistry.Scheme, targetImage.ContainerRegistry.Host)
commonPipelineEnvironment.container.imageNameTag = fmt.Sprintf("%v:%v", targetImage.ContainerImageName, targetImage.ContainerImageTag)
if config.BuildEnvVars != nil && len(config.BuildEnvVars) > 0 {
log.Entry().Infof("Setting custom environment variables: '%v'", config.BuildEnvVars)
err = cnbutils.CreateEnvFiles(utils, platformPath, config.BuildEnvVars)
@@ -322,7 +333,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u
}
var source string
if len(config.Path) > 0 {
if config.Path != "" {
source = config.Path
} else {
source = pwd
@@ -386,28 +397,6 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u
}
}
if len(config.ContainerRegistryURL) == 0 || len(config.ContainerImageName) == 0 || len(config.ContainerImageTag) == 0 {
log.SetErrorCategory(log.ErrorConfiguration)
return errors.New("containerRegistryUrl, containerImageName and containerImageTag must be present")
}
var containerRegistry string
if matched, _ := regexp.MatchString("^(http|https)://.*", config.ContainerRegistryURL); matched {
containerRegistry, err = docker.ContainerRegistryFromURL(config.ContainerRegistryURL)
if err != nil {
log.SetErrorCategory(log.ErrorConfiguration)
return errors.Wrapf(err, "failed to read containerRegistryUrl %s", config.ContainerRegistryURL)
}
commonPipelineEnvironment.container.registryURL = config.ContainerRegistryURL
} else {
containerRegistry = config.ContainerRegistryURL
commonPipelineEnvironment.container.registryURL = fmt.Sprintf("https://%v", config.ContainerRegistryURL)
}
containerImage := path.Join(containerRegistry, config.ContainerImageName)
containerImageTag := strings.ReplaceAll(config.ContainerImageTag, "+", "-")
commonPipelineEnvironment.container.imageNameTag = fmt.Sprintf("%v:%v", config.ContainerImageName, containerImageTag)
if len(config.CustomTLSCertificateLinks) > 0 {
caCertificates := "/tmp/ca-certificates.crt"
_, err := utils.Copy("/etc/ssl/certs/ca-certificates.crt", caCertificates)
@@ -433,6 +422,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u
"-platform", platformPath,
}
containerImage := path.Join(targetImage.ContainerRegistry.Host, targetImage.ContainerImageName)
for _, tag := range config.AdditionalTags {
target := fmt.Sprintf("%s:%s", containerImage, tag)
if !piperutils.ContainsString(creatorArgs, target) {
@@ -440,7 +430,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u
}
}
creatorArgs = append(creatorArgs, fmt.Sprintf("%s:%s", containerImage, containerImageTag))
creatorArgs = append(creatorArgs, fmt.Sprintf("%s:%s", containerImage, targetImage.ContainerImageTag))
err = utils.RunExecutable(creatorPath, creatorArgs...)
if err != nil {
log.SetErrorCategory(log.ErrorBuild)

View File

@@ -154,7 +154,7 @@ func CnbBuildCommand() *cobra.Command {
}
func addCnbBuildFlags(cmd *cobra.Command, stepConfig *cnbBuildOptions) {
cmd.Flags().StringVar(&stepConfig.ContainerImageName, "containerImageName", os.Getenv("PIPER_containerImageName"), "Name of the container which will be built")
cmd.Flags().StringVar(&stepConfig.ContainerImageName, "containerImageName", os.Getenv("PIPER_containerImageName"), "Name of the container which will be built\n`cnbBuild` step will try to identify a containerImageName using the following precedence:\n 1. `containerImageName` parameter.\n 2. `project.id` field of a `project.toml` file.\n 3. `git/repository` parameter of the `commonPipelineEnvironment`.\nIf none of the above was found - an error will be raised.\n")
cmd.Flags().StringVar(&stepConfig.ContainerImageTag, "containerImageTag", os.Getenv("PIPER_containerImageTag"), "Tag of the container which will be built")
cmd.Flags().StringVar(&stepConfig.ContainerRegistryURL, "containerRegistryUrl", os.Getenv("PIPER_containerRegistryUrl"), "Container registry where the image should be pushed to")
cmd.Flags().StringSliceVar(&stepConfig.Buildpacks, "buildpacks", []string{}, "List of custom buildpacks to use in the form of '$HOSTNAME/$REPO[:$TAG]'.")
@@ -165,7 +165,6 @@ func addCnbBuildFlags(cmd *cobra.Command, stepConfig *cnbBuildOptions) {
cmd.Flags().StringSliceVar(&stepConfig.CustomTLSCertificateLinks, "customTlsCertificateLinks", []string{}, "List containing download links of custom TLS certificates. This is required to ensure trusted connections to registries with custom certificates.")
cmd.Flags().StringSliceVar(&stepConfig.AdditionalTags, "additionalTags", []string{}, "List of tags which will be pushed to the registry (additionally to the provided `containerImageTag`), e.g. \"latest\".")
cmd.MarkFlagRequired("containerImageName")
cmd.MarkFlagRequired("containerImageTag")
cmd.MarkFlagRequired("containerRegistryUrl")
}
@@ -189,7 +188,7 @@ func cnbBuildMetadata() config.StepData {
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Mandatory: false,
Aliases: []config.Alias{{Name: "dockerImageName"}},
Default: os.Getenv("PIPER_containerImageName"),
},

View File

@@ -13,6 +13,8 @@ import (
"github.com/stretchr/testify/assert"
)
const imageRegistry = "some-registry"
func newCnbBuildTestsUtils() cnbutils.MockUtils {
utils := cnbutils.MockUtils{
ExecMockRunner: &mock.ExecMockRunner{},
@@ -35,14 +37,73 @@ func assertLifecycleCalls(t *testing.T, runner *mock.ExecMockRunner) {
func TestRunCnbBuild(t *testing.T) {
t.Parallel()
t.Run("success case (registry with https)", func(t *testing.T) {
t.Run("preferes direct configuration", func(t *testing.T) {
t.Parallel()
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
registry := "some-registry"
config := cnbBuildOptions{
ContainerImageName: "my-image",
ContainerImageTag: "0.0.1",
ContainerRegistryURL: fmt.Sprintf("https://%s", registry),
ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry),
DockerConfigJSON: "/path/to/config.json",
}
projectToml := `[project]
id = "io.buildpacks.my-app"
`
utils := newCnbBuildTestsUtils()
utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
utils.FilesMock.AddFile("project.toml", []byte(projectToml))
addBuilderFiles(&utils)
err := runCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
assert.NoError(t, err)
runner := utils.ExecMockRunner
assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
assertLifecycleCalls(t, runner)
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag))
assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL)
assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag)
})
t.Run("preferes project descriptor", func(t *testing.T) {
t.Parallel()
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
config := cnbBuildOptions{
ContainerImageTag: "0.0.1",
ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry),
DockerConfigJSON: "/path/to/config.json",
ProjectDescriptor: "project.toml",
}
projectToml := `[project]
id = "io.buildpacks.my-app"
`
utils := newCnbBuildTestsUtils()
utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
utils.FilesMock.AddFile("project.toml", []byte(projectToml))
addBuilderFiles(&utils)
err := runCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
assert.NoError(t, err)
runner := utils.ExecMockRunner
assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
assertLifecycleCalls(t, runner)
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, "io-buildpacks-my-app", config.ContainerImageTag))
assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL)
assert.Equal(t, "io-buildpacks-my-app:0.0.1", commonPipelineEnvironment.container.imageNameTag)
})
t.Run("success case (registry with https)", func(t *testing.T) {
t.Parallel()
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
config := cnbBuildOptions{
ContainerImageName: "my-image",
ContainerImageTag: "0.0.1",
ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry),
DockerConfigJSON: "/path/to/config.json",
}
@@ -56,19 +117,18 @@ func TestRunCnbBuild(t *testing.T) {
runner := utils.ExecMockRunner
assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
assertLifecycleCalls(t, runner)
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag))
assert.Equal(t, fmt.Sprintf("https://%s", registry), commonPipelineEnvironment.container.registryURL)
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag))
assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL)
assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag)
})
t.Run("success case (registry without https)", func(t *testing.T) {
t.Parallel()
registry := "some-registry"
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
config := cnbBuildOptions{
ContainerImageName: "my-image",
ContainerImageTag: "0.0.1",
ContainerRegistryURL: registry,
ContainerRegistryURL: imageRegistry,
DockerConfigJSON: "/path/to/config.json",
}
@@ -82,19 +142,18 @@ func TestRunCnbBuild(t *testing.T) {
runner := utils.ExecMockRunner
assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
assertLifecycleCalls(t, runner)
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag))
assert.Equal(t, fmt.Sprintf("https://%s", registry), commonPipelineEnvironment.container.registryURL)
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag))
assert.Equal(t, fmt.Sprintf("https://%s", config.ContainerRegistryURL), commonPipelineEnvironment.container.registryURL)
assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag)
})
t.Run("success case (custom buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) {
t.Parallel()
registry := "some-registry"
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
config := cnbBuildOptions{
ContainerImageName: "my-image",
ContainerImageTag: "0.0.1",
ContainerRegistryURL: registry,
ContainerRegistryURL: imageRegistry,
DockerConfigJSON: "/path/to/test.json",
Buildpacks: []string{"test"},
BuildEnvVars: map[string]interface{}{
@@ -115,8 +174,8 @@ func TestRunCnbBuild(t *testing.T) {
assert.Equal(t, creatorPath, runner.Calls[0].Exec)
assert.Contains(t, runner.Calls[0].Params, "/tmp/buildpacks")
assert.Contains(t, runner.Calls[0].Params, "/tmp/buildpacks/order.toml")
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:latest", registry, config.ContainerImageName))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:latest", config.ContainerRegistryURL, config.ContainerImageName))
initialFileExists, _ := utils.FileExists("/path/to/test.json")
renamedFileExists, _ := utils.FileExists("/path/to/config.json")
@@ -162,17 +221,16 @@ func TestRunCnbBuild(t *testing.T) {
assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
assert.Contains(t, runner.Env, fmt.Sprintf("SSL_CERT_FILE=%s", caCertsTmpFile))
assertLifecycleCalls(t, runner)
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag))
})
t.Run("success case (additionalTags)", func(t *testing.T) {
t.Parallel()
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
registry := "some-registry"
config := cnbBuildOptions{
ContainerImageName: "my-image",
ContainerImageTag: "3.1.5",
ContainerRegistryURL: registry,
ContainerRegistryURL: imageRegistry,
DockerConfigJSON: "/path/to/config.json",
AdditionalTags: []string{"3", "3.1", "3.1", "3.1.5"},
}
@@ -186,10 +244,10 @@ func TestRunCnbBuild(t *testing.T) {
runner := utils.ExecMockRunner
assertLifecycleCalls(t, runner)
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3", registry, config.ContainerImageName))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1", registry, config.ContainerImageName))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1.5", registry, config.ContainerImageName))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3", config.ContainerRegistryURL, config.ContainerImageName))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1", config.ContainerRegistryURL, config.ContainerImageName))
assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1.5", config.ContainerRegistryURL, config.ContainerImageName))
})
t.Run("pom.xml exists (symlink for the target folder)", func(t *testing.T) {
@@ -197,7 +255,7 @@ func TestRunCnbBuild(t *testing.T) {
config := cnbBuildOptions{
ContainerImageName: "my-image",
ContainerImageTag: "3.1.5",
ContainerRegistryURL: "some-registry",
ContainerRegistryURL: imageRegistry,
DockerConfigJSON: "/path/to/config.json",
}
@@ -222,7 +280,7 @@ func TestRunCnbBuild(t *testing.T) {
config := cnbBuildOptions{
ContainerImageName: "my-image",
ContainerImageTag: "3.1.5",
ContainerRegistryURL: "some-registry",
ContainerRegistryURL: imageRegistry,
DockerConfigJSON: "/path/to/config.json",
}
@@ -245,8 +303,10 @@ func TestRunCnbBuild(t *testing.T) {
t.Parallel()
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
config := cnbBuildOptions{
ContainerImageName: "my-image",
DockerConfigJSON: "/path/to/config.json",
ContainerImageTag: "0.0.1",
ContainerRegistryURL: imageRegistry,
ContainerImageName: "my-image",
DockerConfigJSON: "/path/to/config.json",
}
utils := newCnbBuildTestsUtils()
@@ -261,8 +321,10 @@ func TestRunCnbBuild(t *testing.T) {
t.Parallel()
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
config := cnbBuildOptions{
ContainerImageName: "my-image",
DockerConfigJSON: "not-there/config.json",
ContainerImageTag: "0.0.1",
ContainerRegistryURL: imageRegistry,
ContainerImageName: "my-image",
DockerConfigJSON: "not-there/config.json",
}
utils := newCnbBuildTestsUtils()
@@ -276,8 +338,10 @@ func TestRunCnbBuild(t *testing.T) {
t.Parallel()
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
config := cnbBuildOptions{
ContainerImageName: "my-image",
DockerConfigJSON: "not-there",
ContainerImageTag: "0.0.1",
ContainerRegistryURL: imageRegistry,
ContainerImageName: "my-image",
DockerConfigJSON: "not-there",
}
utils := newCnbBuildTestsUtils()
@@ -301,11 +365,10 @@ func TestRunCnbBuild(t *testing.T) {
t.Run("error case: builder image does not contain tls certificates", func(t *testing.T) {
t.Parallel()
commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
registry := "some-registry"
config := cnbBuildOptions{
ContainerImageName: "my-image",
ContainerImageTag: "0.0.1",
ContainerRegistryURL: registry,
ContainerRegistryURL: imageRegistry,
DockerConfigJSON: "/path/to/config.json",
Buildpacks: []string{"test"},
CustomTLSCertificateLinks: []string{"http://example.com/certs.pem"},

View File

@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package cmd

View File

@@ -36,8 +36,13 @@ type build struct {
Env []envVar `toml:"env"`
}
type project struct {
ID string `toml:"id"`
}
type projectDescriptor struct {
Build build `toml:"build"`
Project project `toml:"project"`
Metadata map[string]interface{} `toml:"metadata"`
}
@@ -46,26 +51,27 @@ type Descriptor struct {
Include *ignore.GitIgnore
EnvVars map[string]interface{}
Buildpacks []string
ProjectID string
}
func ParseDescriptor(descriptorPath string, utils cnbutils.BuildUtils, httpClient piperhttp.Sender) (Descriptor, error) {
descriptor := Descriptor{}
func ParseDescriptor(descriptorPath string, utils cnbutils.BuildUtils, httpClient piperhttp.Sender) (*Descriptor, error) {
descriptor := &Descriptor{}
descriptorContent, err := utils.FileRead(descriptorPath)
if err != nil {
return Descriptor{}, err
return nil, err
}
rawDescriptor := projectDescriptor{}
err = toml.Unmarshal(descriptorContent, &rawDescriptor)
if err != nil {
return Descriptor{}, err
return nil, err
}
if rawDescriptor.Build.Buildpacks != nil && len(rawDescriptor.Build.Buildpacks) > 0 {
buildpacksImg, err := rawDescriptor.Build.searchBuildpacks(httpClient)
if err != nil {
return Descriptor{}, err
return nil, err
}
descriptor.Buildpacks = buildpacksImg
@@ -76,7 +82,7 @@ func ParseDescriptor(descriptorPath string, utils cnbutils.BuildUtils, httpClien
}
if len(rawDescriptor.Build.Exclude) > 0 && len(rawDescriptor.Build.Include) > 0 {
return Descriptor{}, errors.New("project descriptor options 'exclude' and 'include' are mutually exclusive")
return nil, errors.New("project descriptor options 'exclude' and 'include' are mutually exclusive")
}
if len(rawDescriptor.Build.Exclude) > 0 {
@@ -87,6 +93,10 @@ func ParseDescriptor(descriptorPath string, utils cnbutils.BuildUtils, httpClien
descriptor.Include = ignore.CompileIgnoreLines(rawDescriptor.Build.Include...)
}
if len(rawDescriptor.Project.ID) > 0 {
descriptor.ProjectID = rawDescriptor.Project.ID
}
return descriptor, nil
}

View File

@@ -65,6 +65,8 @@ id = "paketo-buildpacks/nodejs"
assert.Equal(t, descriptor.EnvVars["VAR1"], "VAL1")
assert.Equal(t, descriptor.EnvVars["VAR2"], "VAL2")
assert.Equal(t, descriptor.ProjectID, "io.buildpacks.my-app")
assert.Contains(t, descriptor.Buildpacks, "index.docker.io/test-java@5.9.1")
assert.Contains(t, descriptor.Buildpacks, "index.docker.io/test-nodejs@1.1.1")

View File

@@ -0,0 +1,54 @@
package cnbutils
import (
"fmt"
"net/url"
"path/filepath"
"regexp"
"strings"
"github.com/SAP/jenkins-library/pkg/piperenv"
"github.com/pkg/errors"
)
type TargetImage struct {
ContainerImageName string
ContainerImageTag string
ContainerRegistry *url.URL
}
func GetTargetImage(imageRegistry, imageName, imageTag, projectID, envRootPath string) (*TargetImage, error) {
if imageRegistry == "" || imageTag == "" {
return nil, errors.New("containerRegistryUrl and containerImageTag must be present")
}
targetImage := &TargetImage{
ContainerImageTag: strings.ReplaceAll(imageTag, "+", "-"),
}
if matched, _ := regexp.MatchString("^(http|https)://.*", imageRegistry); !matched {
imageRegistry = fmt.Sprintf("https://%s", imageRegistry)
}
url, err := url.ParseRequestURI(imageRegistry)
if err != nil {
return nil, errors.Wrap(err, "invalid registry url")
}
targetImage.ContainerRegistry = url
cpePath := filepath.Join(envRootPath, "commonPipelineEnvironment")
gitRepository := piperenv.GetResourceParameter(cpePath, "git", "repository")
if imageName != "" {
targetImage.ContainerImageName = imageName
} else if projectID != "" {
name := strings.ReplaceAll(projectID, ".", "-")
targetImage.ContainerImageName = name
} else if gitRepository != "" {
targetImage.ContainerImageName = strings.ReplaceAll(gitRepository, ".", "-")
} else {
return nil, errors.New("failed to derive default for image name")
}
return targetImage, nil
}

View File

@@ -0,0 +1,83 @@
package cnbutils_test
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/SAP/jenkins-library/pkg/cnbutils"
"github.com/stretchr/testify/assert"
)
func TestGetImageName(t *testing.T) {
t.Parallel()
t.Run("Registry without protocol will add https", func(t *testing.T) {
t.Parallel()
targetImage, err := cnbutils.GetTargetImage("registry", "image", "tag", "", "")
assert.NoError(t, err)
assert.Equal(t, "https", targetImage.ContainerRegistry.Scheme)
assert.Equal(t, "registry", targetImage.ContainerRegistry.Host)
})
t.Run("Registry with protocol will keep it", func(t *testing.T) {
t.Parallel()
targetImage, err := cnbutils.GetTargetImage("http://registry", "image", "tag", "", "")
assert.NoError(t, err)
assert.Equal(t, "http", targetImage.ContainerRegistry.Scheme)
assert.Equal(t, "registry", targetImage.ContainerRegistry.Host)
})
t.Run("Image name is taken from the configuration", func(t *testing.T) {
t.Parallel()
targetImage, err := cnbutils.GetTargetImage("http://registry", "image", "tag", "", "")
assert.NoError(t, err)
assert.Equal(t, "image", targetImage.ContainerImageName)
assert.Equal(t, "tag", targetImage.ContainerImageTag)
})
t.Run("Image name is taken from project.toml", func(t *testing.T) {
t.Parallel()
targetImage, err := cnbutils.GetTargetImage("http://registry", "", "tag", "project-id.0", "")
assert.NoError(t, err)
assert.Equal(t, "project-id-0", targetImage.ContainerImageName)
assert.Equal(t, "tag", targetImage.ContainerImageTag)
})
t.Run("Image name is taken from git repo", func(t *testing.T) {
t.Parallel()
tmpdir, err := ioutil.TempDir("", "cpe")
assert.NoError(t, err)
defer os.RemoveAll(tmpdir)
err = os.MkdirAll(filepath.Join(tmpdir, "commonPipelineEnvironment", "git"), os.ModePerm)
assert.NoError(t, err)
err = ioutil.WriteFile(filepath.Join(tmpdir, "commonPipelineEnvironment", "git", "repository"), []byte("repo-name"), os.ModePerm)
assert.NoError(t, err)
targetImage, err := cnbutils.GetTargetImage("http://registry", "", "tag", "", tmpdir)
assert.NoError(t, err)
assert.Equal(t, "repo-name", targetImage.ContainerImageName)
assert.Equal(t, "tag", targetImage.ContainerImageTag)
})
t.Run("throws an error if unable to find image name", func(t *testing.T) {
t.Parallel()
_, err := cnbutils.GetTargetImage("http://registry", "", "tag", "", "")
assert.Error(t, err)
assert.Equal(t, "failed to derive default for image name", err.Error())
})
}

View File

@@ -38,8 +38,13 @@ spec:
aliases:
- name: dockerImageName
type: string
mandatory: true
description: Name of the container which will be built
description: |
Name of the container which will be built
`cnbBuild` step will try to identify a containerImageName using the following precedence:
1. `containerImageName` parameter.
2. `project.id` field of a `project.toml` file.
3. `git/repository` parameter of the `commonPipelineEnvironment`.
If none of the above was found - an error will be raised.
scope:
- GENERAL
- PARAMETERS