builder/build/cnb/version_policy.go
Rama main · réplica de lectura del repositorio original.
package cnb
import (
"fmt"
"strings"
"github.com/goodrain/rainbond/builder/build"
"github.com/goodrain/rainbond/builder/parser/code"
)
type versionPolicyRule struct {
policyKey string
explicitKeys []string
bpKey string
setKeys []string
ossDefault string
}
var versionPolicyRules = map[code.Lang]versionPolicyRule{
code.JavaMaven: {policyKey: "java", explicitKeys: []string{"BUILD_RUNTIMES", "RUNTIMES", "BP_JVM_VERSION"}, bpKey: "BP_JVM_VERSION", setKeys: []string{"BUILD_RUNTIMES", "BP_JVM_VERSION"}, ossDefault: "17"},
code.JaveWar: {policyKey: "java", explicitKeys: []string{"BUILD_RUNTIMES", "RUNTIMES", "BP_JVM_VERSION"}, bpKey: "BP_JVM_VERSION", setKeys: []string{"BUILD_RUNTIMES", "BP_JVM_VERSION"}, ossDefault: "17"},
code.JavaJar: {policyKey: "java", explicitKeys: []string{"BUILD_RUNTIMES", "RUNTIMES", "BP_JVM_VERSION"}, bpKey: "BP_JVM_VERSION", setKeys: []string{"BUILD_RUNTIMES", "BP_JVM_VERSION"}, ossDefault: "17"},
code.Gradle: {policyKey: "java", explicitKeys: []string{"BUILD_RUNTIMES", "RUNTIMES", "BP_JVM_VERSION"}, bpKey: "BP_JVM_VERSION", setKeys: []string{"BUILD_RUNTIMES", "BP_JVM_VERSION"}, ossDefault: "17"},
code.Python: {policyKey: "python", explicitKeys: []string{"BUILD_RUNTIMES", "RUNTIMES", "BP_CPYTHON_VERSION"}, bpKey: "BP_CPYTHON_VERSION", setKeys: []string{"BUILD_RUNTIMES", "BP_CPYTHON_VERSION"}, ossDefault: "3.14"},
code.Golang: {policyKey: "golang", explicitKeys: []string{"BP_GO_VERSION", "BUILD_GOVERSION", "GOVERSION"}, bpKey: "BP_GO_VERSION", setKeys: []string{"BUILD_GOVERSION", "BP_GO_VERSION"}, ossDefault: "1.25"},
code.NetCore: {policyKey: "dotnet", explicitKeys: []string{"BP_DOTNET_FRAMEWORK_VERSION"}, bpKey: "BP_DOTNET_FRAMEWORK_VERSION", setKeys: []string{"BP_DOTNET_FRAMEWORK_VERSION"}, ossDefault: "8.0"},
code.PHP: {policyKey: "php", explicitKeys: []string{"BP_PHP_VERSION", "BUILD_RUNTIMES", "RUNTIMES"}, bpKey: "BP_PHP_VERSION", setKeys: []string{"BUILD_RUNTIMES", "BP_PHP_VERSION"}, ossDefault: "8.3"},
code.Nodejs: {policyKey: "nodejs", explicitKeys: []string{"CNB_NODE_VERSION", "BUILD_RUNTIMES", "RUNTIMES", "BP_NODE_VERSION"}, bpKey: "BP_NODE_VERSION", setKeys: []string{"CNB_NODE_VERSION", "BP_NODE_VERSION"}, ossDefault: "24.13.0"},
}
func applyVersionPolicy(re *build.Request) error {
if strings.TrimSpace(re.BuildStrategy) != "cnb" {
return nil
}
rule, ok := versionPolicyRules[re.Lang]
if !ok {
return nil
}
resolved, err := resolveVersionWithPolicy(re, rule)
if err != nil {
return err
}
if resolved == "" {
return nil
}
if re.BuildEnvs == nil {
re.BuildEnvs = map[string]string{}
}
re.BuildEnvs[rule.bpKey] = resolved
for _, key := range rule.setKeys {
re.BuildEnvs[key] = resolved
}
return nil
}
func resolveVersionWithPolicy(re *build.Request, rule versionPolicyRule) (string, error) {
policy := getLanguagePolicy(re.CNBVersionPolicy, rule.policyKey)
if explicit := firstNonEmptyEnv(re.BuildEnvs, rule.explicitKeys...); explicit != "" {
resolved, err := normalizeVersionByLanguage(re.Lang, explicit)
if err != nil {
return "", err
}
if err := ensureAllowedByPolicy(rule.policyKey, resolved, policy); err != nil {
return "", err
}
return resolved, nil
}
detected, err := detectVersionFromSource(re)
if err != nil {
return "", err
}
if detected != "" {
if err := ensureAllowedByPolicy(rule.policyKey, detected, policy); err != nil {
return "", err
}
return detected, nil
}
if policy != nil && policy.DefaultVersion != "" {
if err := ensureAllowedByPolicy(rule.policyKey, policy.DefaultVersion, policy); err != nil {
return "", err
}
return policy.DefaultVersion, nil
}
return rule.ossDefault, nil
}
func detectVersionFromSource(re *build.Request) (string, error) {
runtimeInfo, err := code.CheckRuntimeByStrategy(re.SourceDir, re.Lang, "cnb")
if err != nil {
return "", err
}
switch re.Lang {
case code.Golang:
return strings.TrimSpace(runtimeInfo["GOVERSION"]), nil
case code.NetCore:
return strings.TrimSpace(runtimeInfo["RUNTIMES"]), nil
default:
return strings.TrimSpace(runtimeInfo["RUNTIMES"]), nil
}
}
func getLanguagePolicy(policy *build.CNBVersionPolicy, key string) *build.CNBLanguagePolicy {
if policy == nil || len(policy.Languages) == 0 {
return nil
}
langPolicy, ok := policy.Languages[key]
if !ok {
return nil
}
return &langPolicy
}
func firstNonEmptyEnv(envs map[string]string, keys ...string) string {
for _, key := range keys {
if value := strings.TrimSpace(envs[key]); value != "" {
return value
}
}
return ""
}
func ensureAllowedByPolicy(policyKey, version string, policy *build.CNBLanguagePolicy) error {
if policy == nil || len(policy.AllowedVersions) == 0 || version == "" {
return nil
}
for _, item := range policy.AllowedVersions {
if item == version {
return nil
}
}
return fmt.Errorf("%s version %s is not allowed by cnb version policy", policyKey, version)
}
func normalizeVersionByLanguage(lang code.Lang, version string) (string, error) {
version = strings.TrimSpace(version)
if version == "" {
return "", nil
}
switch lang {
case code.JavaMaven, code.JaveWar, code.JavaJar, code.Gradle:
if strings.HasPrefix(version, "1.") {
version = version[2:]
}
parts := strings.Split(version, ".")
if len(parts) < 1 || parts[0] == "" {
return "", fmt.Errorf("invalid java cnb version %q", version)
}
return parts[0], nil
case code.Python:
if strings.HasPrefix(version, "python-") {
version = version[len("python-"):]
}
parts := strings.Split(version, ".")
if len(parts) < 2 {
return "", fmt.Errorf("invalid python cnb version %q", version)
}
return strings.Join(parts[:2], "."), nil
case code.Golang:
if strings.HasPrefix(version, "go") {
version = version[2:]
}
parts := strings.Split(version, ".")
if len(parts) < 2 {
return "", fmt.Errorf("invalid golang cnb version %q", version)
}
return strings.Join(parts[:2], "."), nil
case code.PHP:
parts := strings.Split(version, ".")
if len(parts) < 2 {
return "", fmt.Errorf("invalid php cnb version %q", version)
}
return strings.Join(parts[:2], "."), nil
case code.NetCore:
version = strings.TrimPrefix(strings.ToLower(version), "net")
parts := strings.Split(version, ".")
if len(parts) < 2 {
return "", fmt.Errorf("invalid dotnet cnb version %q", version)
}
return strings.Join(parts[:2], "."), nil
case code.Nodejs:
return normalizeNodeVersion(version)
default:
return version, nil
}
}
func normalizeNodeVersion(version string) (string, error) {
if strings.TrimSpace(version) == "" {
return "", nil
}
if !strings.ContainsAny(version, "0123456789") {
return "", fmt.Errorf("invalid nodejs cnb version %q", version)
}
resolved := code.MatchCNBVersion("nodejs", version)
if resolved == "" {
return "", fmt.Errorf("invalid nodejs cnb version %q", version)
}
return resolved, nil
}