diff --git a/cmd/werf/bundle/publish/publish.go b/cmd/werf/bundle/publish/publish.go index e5c08dc467..74e981870b 100644 --- a/cmd/werf/bundle/publish/publish.go +++ b/cmd/werf/bundle/publish/publish.go @@ -375,9 +375,10 @@ func runPublish(ctx context.Context, imageNameListFromArgs []string) error { } if vals, err := helpers.GetServiceValues(ctx, werfConfig.Meta.Project, imagesRepo, imagesInfoGetters, helpers.ServiceValuesOptions{ - Env: *commonCmdData.Environment, - CommitHash: headHash, - CommitDate: headTime, + ApplicationVersion: werfConfig.Meta.ApplicationVersion, + Env: *commonCmdData.Environment, + CommitHash: headHash, + CommitDate: headTime, }); err != nil { return fmt.Errorf("error creating service values: %w", err) } else { diff --git a/cmd/werf/converge/converge.go b/cmd/werf/converge/converge.go index d4f2e6e2bc..467b5fe192 100644 --- a/cmd/werf/converge/converge.go +++ b/cmd/werf/converge/converge.go @@ -525,14 +525,16 @@ func run( return fmt.Errorf("get HEAD commit time: %w", err) } - if vals, err := helpers.GetServiceValues(ctx, werfConfig.Meta.Project, imagesRepo, imagesInfoGetters, helpers.ServiceValuesOptions{ - Namespace: releaseNamespace, - Env: *commonCmdData.Environment, - SetDockerConfigJsonValue: *commonCmdData.SetDockerConfigJsonValue, - DockerConfigPath: filepath.Dir(registryCredentialsPath), - CommitHash: headHash, - CommitDate: headTime, - }); err != nil { + if vals, err := helpers.GetServiceValues(ctx, werfConfig.Meta.Project, imagesRepo, imagesInfoGetters, + helpers.ServiceValuesOptions{ + ApplicationVersion: werfConfig.Meta.ApplicationVersion, + Namespace: releaseNamespace, + Env: *commonCmdData.Environment, + SetDockerConfigJsonValue: *commonCmdData.SetDockerConfigJsonValue, + DockerConfigPath: filepath.Dir(registryCredentialsPath), + CommitHash: headHash, + CommitDate: headTime, + }); err != nil { return fmt.Errorf("get service values: %w", err) } else { wc.SetServiceValues(vals) diff --git a/cmd/werf/helm/get_autogenerated_values.go b/cmd/werf/helm/get_autogenerated_values.go index 39eeff1496..aa92cf2d48 100644 --- a/cmd/werf/helm/get_autogenerated_values.go +++ b/cmd/werf/helm/get_autogenerated_values.go @@ -307,11 +307,12 @@ func runGetServiceValues(ctx context.Context, imageNameListFromArgs []string) er } vals, err := helpers.GetServiceValues(ctx, werfConfig.Meta.Project, imagesRepository, imagesInfoGetters, helpers.ServiceValuesOptions{ - Namespace: releaseNamespace, - Env: *commonCmdData.Environment, - IsStub: isStub, - DisableEnvStub: true, - StubImageNameList: stubImageNameList, SetDockerConfigJsonValue: *commonCmdData.SetDockerConfigJsonValue, + ApplicationVersion: werfConfig.Meta.ApplicationVersion, + Namespace: releaseNamespace, + Env: *commonCmdData.Environment, + IsStub: isStub, + DisableEnvStub: true, + StubImageNameList: stubImageNameList, SetDockerConfigJsonValue: *commonCmdData.SetDockerConfigJsonValue, DockerConfigPath: filepath.Dir(registryCredentialsPath), CommitHash: headHash, CommitDate: headTime, diff --git a/cmd/werf/plan/plan.go b/cmd/werf/plan/plan.go index d0ef6faa19..ec5987161c 100644 --- a/cmd/werf/plan/plan.go +++ b/cmd/werf/plan/plan.go @@ -508,6 +508,7 @@ func run( } if vals, err := helpers.GetServiceValues(ctx, werfConfig.Meta.Project, imagesRepository, imagesInfoGetters, helpers.ServiceValuesOptions{ + ApplicationVersion: werfConfig.Meta.ApplicationVersion, Namespace: releaseNamespace, Env: *commonCmdData.Environment, IsStub: isStub, diff --git a/cmd/werf/render/render.go b/cmd/werf/render/render.go index 8baef8c1ed..b89ddfcac8 100644 --- a/cmd/werf/render/render.go +++ b/cmd/werf/render/render.go @@ -468,6 +468,7 @@ func runRender(ctx context.Context, imageNameListFromArgs []string) error { } if vals, err := helpers.GetServiceValues(ctx, werfConfig.Meta.Project, imagesRepository, imagesInfoGetters, helpers.ServiceValuesOptions{ + ApplicationVersion: werfConfig.Meta.ApplicationVersion, Namespace: releaseNamespace, Env: *commonCmdData.Environment, IsStub: isStub, diff --git a/pkg/config/meta.go b/pkg/config/meta.go index 9fcc377a33..62f7c29302 100644 --- a/pkg/config/meta.go +++ b/pkg/config/meta.go @@ -1,10 +1,12 @@ package config type Meta struct { - ConfigVersion int - Project string - Deploy MetaDeploy - Cleanup MetaCleanup - GitWorktree MetaGitWorktree - Build MetaBuild + ApplicationVersion string + ApplicationVersionFile string + ConfigVersion int + Project string + Deploy MetaDeploy + Cleanup MetaCleanup + GitWorktree MetaGitWorktree + Build MetaBuild } diff --git a/pkg/config/parser.go b/pkg/config/parser.go index 4862d1e5d5..acaa881a7c 100644 --- a/pkg/config/parser.go +++ b/pkg/config/parser.go @@ -1,8 +1,10 @@ package config import ( + "bufio" "bytes" "context" + "encoding/json" "errors" "fmt" "os" @@ -116,6 +118,15 @@ func GetWerfConfig(ctx context.Context, customWerfConfigRelPath, customWerfConfi return "", nil, fmt.Errorf(format, defaultProjectName) } + if meta.ApplicationVersionFile != "" { + applicationVersion, err := getApplicationVersionFromFile(meta.ApplicationVersionFile, giterminismManager) + if err != nil { + return "", nil, err + } + + meta.ApplicationVersion = applicationVersion + } + werfConfig, err := prepareWerfConfig(giterminismManager, rawStapelImages, rawImagesFromDockerfile, meta) if err != nil { return "", nil, err @@ -142,6 +153,65 @@ func GetDefaultProjectName(ctx context.Context, giterminismManager giterminism_m return slug.Project(name), nil } +func getApplicationVersionFromFile(path string, giterminismManager giterminism_manager.Interface) (string, error) { + absolutePath := util.GetAbsoluteFilepath(path) + if !util.IsSubpathOfBasePath(giterminismManager.LocalGitRepo().GetWorkTreeDir(), path) && !giterminismManager.Dev() { + return "", fmt.Errorf("application version file %q must be in the project git work tree %q", path, giterminismManager.LocalGitRepo().GetWorkTreeDir()) + } + + r, err := os.Open(absolutePath) + if err != nil { + return "", fmt.Errorf("cannot read applicationVersionFile %s: %w", absolutePath, err) + } + defer r.Close() + + type versionFileType struct { + Version string `yaml:"version" json:"version"` + } + + var applicationVersion string + + switch filepath.Ext(absolutePath) { + case ".yaml", ".yml": + var data versionFileType + + err = yaml.NewDecoder(r).Decode(&data) + if err != nil { + return "", fmt.Errorf("cannot read application version from applicationVersionFile %s: %w", absolutePath, err) + } + + applicationVersion = data.Version + case ".json": + var data versionFileType + + err = json.NewDecoder(r).Decode(&data) + if err != nil { + return "", fmt.Errorf("cannot read application version from applicationVersionFile %s: %w", absolutePath, err) + } + + applicationVersion = data.Version + case "": + scanner := bufio.NewScanner(r) + + if scanner.Scan() { + applicationVersion = scanner.Text() + } + + err = scanner.Err() + if err != nil { + return "", fmt.Errorf("cannot read application version from applicationVersionFile %s", absolutePath) + } + default: + return "", fmt.Errorf("applicationVersionFile %s has unsupported file extension", absolutePath) + } + + if len(applicationVersion) == 0 { + return "", fmt.Errorf("applicationVersionFile %s does not specify application version", absolutePath) + } + + return applicationVersion, nil +} + func writeWerfConfigRender(werfConfigRenderContent, werfConfigRenderPath string) error { werfConfigRenderFile, err := os.OpenFile(werfConfigRenderPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644) if err != nil { @@ -596,6 +666,14 @@ func isMetaDoc(h map[string]interface{}) bool { return true } + if _, ok := h["applicationVersion"]; ok { + return true + } + + if _, ok := h["applicationVersionFile"]; ok { + return true + } + return false } diff --git a/pkg/config/raw_meta.go b/pkg/config/raw_meta.go index f0a35c501f..fdc4ff589f 100644 --- a/pkg/config/raw_meta.go +++ b/pkg/config/raw_meta.go @@ -8,12 +8,14 @@ import ( ) type rawMeta struct { - ConfigVersion *int `yaml:"configVersion,omitempty"` - Project *string `yaml:"project,omitempty"` - Build *rawMetaBuild `yaml:"build,omitempty"` - Deploy *rawMetaDeploy `yaml:"deploy,omitempty"` - Cleanup *rawMetaCleanup `yaml:"cleanup,omitempty"` - GitWorktree *rawMetaGitWorktree `yaml:"gitWorktree,omitempty"` + ApplicationVersion *string `yaml:"applicationVersion,omitempty"` + ApplicationVersionFile *string `yaml:"applicationVersionFile,omitempty"` + ConfigVersion *int `yaml:"configVersion,omitempty"` + Project *string `yaml:"project,omitempty"` + Build *rawMetaBuild `yaml:"build,omitempty"` + Deploy *rawMetaDeploy `yaml:"deploy,omitempty"` + Cleanup *rawMetaCleanup `yaml:"cleanup,omitempty"` + GitWorktree *rawMetaGitWorktree `yaml:"gitWorktree,omitempty"` doc *doc `yaml:"-"` // parent @@ -41,6 +43,10 @@ func (c *rawMeta) UnmarshalYAML(unmarshal func(interface{}) error) error { return newDetailedConfigError("'project' field cannot be empty!", nil, c.doc) } + if c.ApplicationVersion != nil && c.ApplicationVersionFile != nil { + return newDetailedConfigError("use either 'applicationVersion' or 'applicationVersionFile' config param", nil, c.doc) + } + if err := slug.ValidateProject(*c.Project); err != nil { return newDetailedConfigError(fmt.Sprintf("bad project name %q specified in config: %s", *c.Project, err), nil, c.doc) } @@ -55,6 +61,14 @@ func (c *rawMeta) toMeta() *Meta { meta.ConfigVersion = *c.ConfigVersion } + if c.ApplicationVersion != nil { + meta.ApplicationVersion = *c.ApplicationVersion + } + + if c.ApplicationVersionFile != nil { + meta.ApplicationVersionFile = *c.ApplicationVersionFile + } + if c.Project != nil { werfProjectName := os.Getenv("WERF_PROJECT_NAME") if werfProjectName != "" { diff --git a/pkg/deploy/helm/chart_extender/helpers/service_values.go b/pkg/deploy/helm/chart_extender/helpers/service_values.go index 181f1de3f1..ccc7ed004f 100644 --- a/pkg/deploy/helm/chart_extender/helpers/service_values.go +++ b/pkg/deploy/helm/chart_extender/helpers/service_values.go @@ -34,10 +34,11 @@ func (d *ChartExtenderServiceValuesData) SetServiceValues(vals map[string]interf } type ServiceValuesOptions struct { - Namespace string - Env string - IsStub bool - StubImageNameList []string + ApplicationVersion string + Namespace string + Env string + IsStub bool + StubImageNameList []string // disable env stub used in the werf-render command DisableEnvStub bool CommitHash string @@ -82,6 +83,10 @@ func GetServiceValues(ctx context.Context, projectName, repo string, imageInfoGe }, } + if opts.ApplicationVersion != "" { + werfInfo["applicationVersion"] = opts.ApplicationVersion + } + if opts.Env != "" { globalInfo["env"] = opts.Env werfInfo["env"] = opts.Env