diff --git a/config/serverless-operator.yaml b/config/serverless-operator.yaml index fe771ab2d..be76febcb 100644 --- a/config/serverless-operator.yaml +++ b/config/serverless-operator.yaml @@ -33,6 +33,7 @@ config: - onDemand: true version: "4.14" promotion: {} + golangVersion: "1.25" release-1.35: konflux: enabled: true @@ -161,6 +162,7 @@ config: promotion: {} prowgen: disabled: true + golangVersion: "1.25" repositories: - customConfigs: - name: 420-aws-ovn diff --git a/pkg/dockerfilegen/generator.go b/pkg/dockerfilegen/generator.go index 3b3b8b46a..8432d34a6 100644 --- a/pkg/dockerfilegen/generator.go +++ b/pkg/dockerfilegen/generator.go @@ -17,6 +17,7 @@ import ( "strings" "text/template" + "github.com/openshift-knative/hack/config" "github.com/openshift-knative/hack/pkg/soversion" "github.com/coreos/go-semver/semver" @@ -150,11 +151,11 @@ func generateDockerfile(params Params, mainPackagesPaths sets.Set[string]) error if err != nil { return err } - goVersion := goMod.Go.Version + goModGoVersion := goMod.Go.Version // The builder images are distinguished by golang major.minor, so we ignore the rest of the goVersion - if strings.Count(goVersion, ".") > 1 { - goVersion = strings.Join(strings.Split(goVersion, ".")[0:2], ".") + if strings.Count(goModGoVersion, ".") > 1 { + goModGoVersion = strings.Join(strings.Split(goModGoVersion, ".")[0:2], ".") } metadata, err := project.ReadMetadataFile(params.ProjectFilePath) @@ -167,6 +168,15 @@ func generateDockerfile(params Params, mainPackagesPaths sets.Set[string]) error metadata = project.DefaultMetadata() } + // get target go version + goVersion, err := goVersionFromConfig(metadata) + if err != nil { + return fmt.Errorf("failed to get Go version from config: %w", err) + } + if goVersion == nil { + goVersion = &goModGoVersion + } + rhelVersion := RHEL9 templateFilePattern := "dockerfile-templates/rhel-9/*.tmpl" var soVersion string @@ -210,7 +220,7 @@ func generateDockerfile(params Params, mainPackagesPaths sets.Set[string]) error builderImage := params.DockerfileImageBuilderFmt if builderImage == "" { - builderImage = builderImageForGoVersion(goVersion, rhelVersion) + builderImage = builderImageForGoVersion(*goVersion, rhelVersion) } else { // Builder image might be provided without formatting '%s' string as plain value if strings.Count(params.DockerfileImageBuilderFmt, "%s") == 1 { @@ -408,6 +418,95 @@ func generateDockerfile(params Params, mainPackagesPaths sets.Set[string]) error return nil } +// goVersionFromConfig returns the target go version for the project. +// First it checks if a dedicated go version is defined for the repositories branch in the config. +// If no repo-branch specific config is set, it uses the one from the coresponding SO branch config. +// If SO does not have a default go version in it's config neither it returns nil to let the caller +// decide. +func goVersionFromConfig(metadata *project.Metadata) (*string, error) { + // get repo config + if imagePrefix := metadata.Project.ImagePrefix; imagePrefix != "" { + + // this is a component repo + branch := "" + if metadata.Project.Tag == "knative-nightly" { + branch = "release-next" + } else { + branch = fmt.Sprintf("release-%s", strings.TrimPrefix(metadata.Project.Tag, "knative-")) + } + + configFiles, err := fs.ReadDir(config.Configs, ".") + if err != nil { + return nil, fmt.Errorf("failed to read config directory: %w", err) + } + + for _, configFile := range configFiles { + if configFile.IsDir() { + continue + } + + content, err := fs.ReadFile(config.Configs, configFile.Name()) + if err != nil { + return nil, fmt.Errorf("failed to load config from %s: %w", configFile.Name(), err) + } + + cfg, err := prowgen.UnmarshalConfig(content) + if err != nil { + return nil, fmt.Errorf("failed to parse config from %s: %w", configFile.Name(), err) + } + + for _, repo := range cfg.Repositories { + if repo.ImagePrefix == imagePrefix { + // this is the repo we are generating the dockerfile for + + if branchConfig, ok := cfg.Config.Branches[branch]; ok { + if branchConfig.GolangVersion != nil && *branchConfig.GolangVersion != "" { + return branchConfig.GolangVersion, nil + } + // we didn't find a repo-branch specific default --> fall back to SO default + } + } + } + } + } + + // check SO config + soBranch := "" + if metadata.Project.Tag != "" { + // this is a component repo (-> we falled through, as we didn't find a repo-branch specific default + if metadata.Project.Tag == "knative-nightly" || metadata.Project.Tag == "main" { + soBranch = "main" + } else { + soVersion := soversion.FromUpstreamVersion(strings.TrimPrefix(metadata.Project.Tag, "knative-")) + soBranch = soversion.BranchName(soVersion) + } + } else if metadata.Project.Version != "" { + majorMinor := strings.TrimSuffix(metadata.Project.Version, ".0") + soBranch = fmt.Sprintf("release-v%s", majorMinor) + } + + if soBranch != "" { + soYaml, err := config.Configs.ReadFile("serverless-operator.yaml") + if err != nil { + return nil, fmt.Errorf("failed to load config for serverless-operator: %w", err) + } + + soConfig, err := prowgen.UnmarshalConfig(soYaml) + if err != nil { + return nil, fmt.Errorf("failed to parse config for serverless-operator: %w", err) + } + + if cfg, ok := soConfig.Config.Branches[soBranch]; ok { + if cfg.GolangVersion != nil && *cfg.GolangVersion != "" { + return cfg.GolangVersion, nil + } + // we didn't find a repo-branch specific default --> fall back to go.mod version + } + } + + return nil, nil +} + func hasVendorFolder(dir string) (bool, error) { info, err := os.Stat(path.Join(dir, "vendor")) if err == nil { diff --git a/pkg/project/testoutput/openshift/ci-operator/build-image/Dockerfile b/pkg/project/testoutput/openshift/ci-operator/build-image/Dockerfile index c7e989748..54684da50 100755 --- a/pkg/project/testoutput/openshift/ci-operator/build-image/Dockerfile +++ b/pkg/project/testoutput/openshift/ci-operator/build-image/Dockerfile @@ -3,7 +3,7 @@ FROM registry.ci.openshift.org/ocp/4.19:cli-artifacts as tools # Dockerfile to bootstrap build and test in openshift-ci -FROM registry.ci.openshift.org/openshift/release:rhel-9-release-golang-1.22-openshift-4.17 as builder +FROM registry.ci.openshift.org/openshift/release:rhel-9-release-golang-1.25-openshift-4.21 as builder ARG TARGETARCH diff --git a/pkg/project/testoutput/openshift/ci-operator/knative-images/discover/Dockerfile b/pkg/project/testoutput/openshift/ci-operator/knative-images/discover/Dockerfile index 2c552f2b0..2276d0961 100755 --- a/pkg/project/testoutput/openshift/ci-operator/knative-images/discover/Dockerfile +++ b/pkg/project/testoutput/openshift/ci-operator/knative-images/discover/Dockerfile @@ -1,5 +1,5 @@ # DO NOT EDIT! Generated Dockerfile for cmd/discover. -ARG GO_BUILDER=registry.ci.openshift.org/openshift/release:rhel-9-release-golang-1.22-openshift-4.17 +ARG GO_BUILDER=registry.ci.openshift.org/openshift/release:rhel-9-release-golang-1.25-openshift-4.21 ARG GO_RUNTIME=registry.access.redhat.com/ubi9/ubi-minimal FROM $GO_BUILDER as builder diff --git a/pkg/prowgen/prowgen_config.go b/pkg/prowgen/prowgen_config.go index 5350c89ea..b5cf2bf2c 100644 --- a/pkg/prowgen/prowgen_config.go +++ b/pkg/prowgen/prowgen_config.go @@ -91,6 +91,7 @@ type Branch struct { SkipE2EMatches []string `json:"skipE2EMatches,omitempty" yaml:"skipE2EMatches,omitempty"` SkipDockerFilesMatches []string `json:"skipDockerFilesMatches,omitempty" yaml:"skipDockerFilesMatches,omitempty"` Konflux *Konflux `json:"konflux,omitempty" yaml:"konflux,omitempty"` + GolangVersion *string `json:"golangVersion,omitempty" yaml:"golangVersion,omitempty"` // DependabotEnabled enabled if `nil`. DependabotEnabled *bool `json:"dependabotEnabled,omitempty" yaml:"dependabotEnabled,omitempty"`