From 2428b4071ddae12c52a21d64dfd209440b36c044 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Mon, 28 Jul 2025 02:58:32 +0530 Subject: [PATCH 01/10] refactor: update chart handling and dependency management in GitOps operations --- cmd/external-app/wire_gen.go | 2 +- internal/util/ChartTemplateService.go | 41 ++-- pkg/appStore/bean/bean.go | 9 +- pkg/appStore/installedApp/adapter/Adapter.go | 7 +- .../deployment/InstalledAppGitOpsService.go | 175 ++++++++++++++---- .../installedApp/service/bean/bean.go | 6 +- .../common/AppStoreDeploymentCommonService.go | 71 +++---- .../gitOps/git/GitOperationService.go | 42 +++-- .../chartRef/ChartRefService.go | 2 +- .../deploymentTemplate/chartRef/bean/bean.go | 2 + 10 files changed, 226 insertions(+), 131 deletions(-) diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index dff24a6755..2209ef41f5 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -1,6 +1,6 @@ // Code generated by Wire. DO NOT EDIT. -//go:generate go run -mod=mod github.com/google/wire/cmd/wire +//go:generate go run github.com/google/wire/cmd/wire //go:build !wireinject // +build !wireinject diff --git a/internal/util/ChartTemplateService.go b/internal/util/ChartTemplateService.go index b03c86dfa5..8eb4e76819 100644 --- a/internal/util/ChartTemplateService.go +++ b/internal/util/ChartTemplateService.go @@ -22,6 +22,7 @@ import ( "encoding/json" "fmt" dockerRegistryRepository "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry" + chartRefBean "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" dirCopy "github.com/otiai10/copy" "go.opentelemetry.io/otel" "go.uber.org/zap" @@ -60,7 +61,7 @@ type ChartCreateRequest struct { type ChartCreateResponse struct { BuiltChartPath string - valuesYaml string + ChartMetaData *chart.Metadata } type ChartTemplateService interface { @@ -74,7 +75,7 @@ type ChartTemplateService interface { LoadChartInBytes(ChartPath string, deleteChart bool) ([]byte, error) LoadChartFromDir(dir string) (*chart.Chart, error) CreateZipFileForChart(chart *chart.Chart, outputChartPathDir string) ([]byte, error) - PackageChart(tempReferenceTemplateDir string, chartMetaData *chart.Metadata) (*string, string, error) + PackageChart(tempReferenceTemplateDir string, chartMetaData *chart.Metadata) (*chart.Metadata, *string, string, error) } type ChartTemplateServiceImpl struct { @@ -105,7 +106,7 @@ func (impl ChartTemplateServiceImpl) GetChartVersion(location string) (string, e return "", fmt.Errorf("%q is not a directory", location) } - chartYaml := filepath.Join(location, "Chart.yaml") + chartYaml := filepath.Join(location, chartRefBean.CHART_YAML_FILE) if _, err := os.Stat(chartYaml); os.IsNotExist(err) { return "", fmt.Errorf("Chart.yaml file not present in the directory %q", location) } @@ -135,7 +136,7 @@ func (impl ChartTemplateServiceImpl) FetchValuesFromReferenceChart(chartMetaData impl.logger.Errorw("error in copying chart for app", "app", chartMetaData.Name, "error", err) return nil, err } - archivePath, valuesYaml, err := impl.PackageChart(chartDir, chartMetaData) + _, archivePath, valuesYaml, err := impl.PackageChart(chartDir, chartMetaData) if err != nil { impl.logger.Errorw("error in creating archive", "err", err) return nil, err @@ -175,7 +176,7 @@ func (impl ChartTemplateServiceImpl) BuildChart(ctx context.Context, chartMetaDa return "", err } _, span := otel.Tracer("orchestrator").Start(ctx, "impl.PackageChart") - _, _, err = impl.PackageChart(tempReferenceTemplateDir, chartMetaData) + _, _, _, err = impl.PackageChart(tempReferenceTemplateDir, chartMetaData) span.End() if err != nil { impl.logger.Errorw("error in creating archive", "err", err) @@ -190,25 +191,24 @@ func (impl ChartTemplateServiceImpl) BuildChartProxyForHelmApps(chartCreateReque chartMetaData.APIVersion = "v2" // ensure always v2 dir := impl.GetDir() chartDir := filepath.Join(CHART_WORKING_DIR_PATH, dir) - impl.logger.Debugw("chart dir ", "chart", chartMetaData.Name, "dir", chartDir) + chartCreateResponse.BuiltChartPath = chartDir + impl.logger.Debugw("temp chart dir", "chart", chartMetaData.Name, "dir", chartDir) err := os.MkdirAll(chartDir, os.ModePerm) //hack for concurrency handling if err != nil { impl.logger.Errorw("err in creating dir", "dir", chartDir, "err", err) return chartCreateResponse, err } err = dirCopy.Copy(chartCreateRequest.ChartPath, chartDir) - if err != nil { impl.logger.Errorw("error in copying chart for app", "app", chartMetaData.Name, "error", err) return chartCreateResponse, err } - _, valuesYaml, err := impl.PackageChart(chartDir, chartMetaData) + chartMetaData, _, _, err = impl.PackageChart(chartDir, chartMetaData) if err != nil { impl.logger.Errorw("error in creating archive", "err", err) return chartCreateResponse, err } - chartCreateResponse.valuesYaml = valuesYaml - chartCreateResponse.BuiltChartPath = chartDir + chartCreateResponse.ChartMetaData = chartMetaData return chartCreateResponse, nil } @@ -298,12 +298,15 @@ func (impl ChartTemplateServiceImpl) overrideChartMetaDataInDir(chartDir string, if len(chartMetaData.Version) > 0 { chart.Metadata.Version = chartMetaData.Version } + if len(chartMetaData.Dependencies) > 0 { + chart.Metadata.Dependencies = append(chart.Metadata.Dependencies, chartMetaData.Dependencies...) + } chartMetaDataBytes, err := yaml.Marshal(chart.Metadata) if err != nil { impl.logger.Errorw("error in marshaling chartMetadata", "err", err) return chart, err } - err = ioutil.WriteFile(filepath.Join(chartDir, "Chart.yaml"), chartMetaDataBytes, 0600) + err = os.WriteFile(filepath.Join(chartDir, chartRefBean.CHART_YAML_FILE), chartMetaDataBytes, 0600) if err != nil { impl.logger.Errorw("err in writing Chart.yaml", "err", err) return chart, err @@ -311,39 +314,39 @@ func (impl ChartTemplateServiceImpl) overrideChartMetaDataInDir(chartDir string, return chart, nil } -func (impl ChartTemplateServiceImpl) PackageChart(tempReferenceTemplateDir string, chartMetaData *chart.Metadata) (*string, string, error) { +func (impl ChartTemplateServiceImpl) PackageChart(tempReferenceTemplateDir string, chartMetaData *chart.Metadata) (*chart.Metadata, *string, string, error) { valid, err := chartutil.IsChartDir(tempReferenceTemplateDir) if err != nil { impl.logger.Errorw("error in validating base chart", "dir", tempReferenceTemplateDir, "err", err) - return nil, "", err + return nil, nil, "", err } if !valid { impl.logger.Errorw("invalid chart at ", "dir", tempReferenceTemplateDir) - return nil, "", fmt.Errorf("invalid base chart") + return nil, nil, "", fmt.Errorf("invalid base chart") } chart, err := impl.overrideChartMetaDataInDir(tempReferenceTemplateDir, chartMetaData) if err != nil { impl.logger.Errorw("error in overriding chart metadata", "chartPath", tempReferenceTemplateDir, "err", err) - return nil, "", err + return nil, nil, "", err } archivePath, err := chartutil.Save(chart, tempReferenceTemplateDir) if err != nil { impl.logger.Errorw("error in saving", "err", err, "dir", tempReferenceTemplateDir) - return nil, "", err + return nil, nil, "", err } impl.logger.Debugw("chart archive path", "path", archivePath) var valuesYaml string byteValues, err := json.Marshal(chart.Values) if err != nil { impl.logger.Errorw("error in json Marshal values", "values", chart.Values, "err", err) - return nil, "", err + return nil, nil, "", err } if chart.Values != nil { valuesYaml = string(byteValues) } else { impl.logger.Warnw("values.yaml not found in helm chart", "dir", tempReferenceTemplateDir) } - return &archivePath, valuesYaml, nil + return chart.Metadata, &archivePath, valuesYaml, nil } func (impl ChartTemplateServiceImpl) CleanDir(dir string) { @@ -376,7 +379,7 @@ func (impl ChartTemplateServiceImpl) GetByteArrayRefChart(chartMetaData *chart.M impl.logger.Errorw("error in copying chart for app", "app", chartMetaData.Name, "error", err) return nil, err } - activePath, _, err := impl.PackageChart(tempReferenceTemplateDir, chartMetaData) + _, activePath, _, err := impl.PackageChart(tempReferenceTemplateDir, chartMetaData) if err != nil { impl.logger.Errorw("error in creating archive", "err", err) return nil, err diff --git a/pkg/appStore/bean/bean.go b/pkg/appStore/bean/bean.go index 1dfe17b5c6..601b146cc0 100644 --- a/pkg/appStore/bean/bean.go +++ b/pkg/appStore/bean/bean.go @@ -31,6 +31,7 @@ import ( "github.com/devtron-labs/devtron/pkg/cluster/environment/bean" bean2 "github.com/devtron-labs/devtron/pkg/deployment/common/bean" "github.com/devtron-labs/devtron/util" + "helm.sh/helm/v3/pkg/chart" "slices" "time" ) @@ -298,7 +299,6 @@ func (chart *InstallAppVersionDTO) GetFluxDeploymentConfig() *bean2.DeploymentCo } } -// / type RefChartProxyDir string const ( @@ -337,12 +337,7 @@ type AppNames struct { } type Dependencies struct { - Dependencies []Dependency `json:"dependencies"` -} -type Dependency struct { - Name string `json:"name"` - Version string `json:"version"` - Repository string `json:"repository"` + Dependencies []*chart.Dependency `json:"dependencies"` } const REFERENCE_TYPE_DEFAULT string = "DEFAULT" diff --git a/pkg/appStore/installedApp/adapter/Adapter.go b/pkg/appStore/installedApp/adapter/Adapter.go index d48360e61a..50ce1afc34 100644 --- a/pkg/appStore/installedApp/adapter/Adapter.go +++ b/pkg/appStore/installedApp/adapter/Adapter.go @@ -41,12 +41,13 @@ func ParseChartGitPushRequest(installAppRequestDTO *appStoreBean.InstallAppVersi } } -func ParseChartCreateRequest(appName string, includePackageChart bool) *util.ChartCreateRequest { +func ParseChartCreateRequest(appName string, dependencies []*chart.Dependency, includePackageChart bool) *util.ChartCreateRequest { chartPath := getRefProxyChartPath() return &util.ChartCreateRequest{ ChartMetaData: &chart.Metadata{ - Name: appName, - Version: "1.0.1", // TODO Asutoh: Why not the actual version? + Name: appName, + Version: "1.0.1", // TODO Asutoh: Why not the actual version? + Dependencies: dependencies, }, ChartPath: chartPath, IncludePackageChart: includePackageChart, diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index 9678b87979..5daf1fc26f 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -18,6 +18,7 @@ package deployment import ( "context" + "encoding/json" "fmt" bean2 "github.com/devtron-labs/devtron/api/bean/gitOps" "github.com/devtron-labs/devtron/internal/util" @@ -27,12 +28,18 @@ import ( "github.com/devtron-labs/devtron/pkg/appStore/installedApp/service/bean" commonBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/common/bean" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git" + gitBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" validationBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/validation/bean" + chartRefBean "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" globalUtil "github.com/devtron-labs/devtron/util" + "github.com/devtron-labs/devtron/util/sliceUtil" "github.com/google/go-github/github" "github.com/microsoft/azure-devops-go-api/azuredevops" "github.com/xanzy/go-gitlab" + "helm.sh/helm/v3/pkg/chart" "net/http" + "os" + "path/filepath" "strconv" "strings" ) @@ -57,7 +64,7 @@ type InstalledAppGitOpsService interface { // GitOpsOperations handles all git operations for Helm App; and ensures that the return param bean.AppStoreGitOpsResponse is not nil func (impl *FullModeDeploymentServiceImpl) GitOpsOperations(manifestResponse *bean.AppStoreManifestResponse, installAppVersionRequest *appStoreBean.InstallAppVersionDTO) (*bean.AppStoreGitOpsResponse, error) { appStoreGitOpsResponse := &bean.AppStoreGitOpsResponse{} - chartGitAttribute, githash, err := impl.createGitOpsRepoAndPushChart(installAppVersionRequest, manifestResponse.ChartResponse.BuiltChartPath, manifestResponse.RequirementsConfig, manifestResponse.ValuesConfig) + chartGitAttribute, githash, err := impl.createGitOpsRepoAndPushChart(installAppVersionRequest, manifestResponse.ChartResponse.BuiltChartPath, manifestResponse.ValuesConfig) if err != nil { impl.Logger.Errorw("Error in pushing chart to git", "err", err) return appStoreGitOpsResponse, err @@ -68,26 +75,31 @@ func (impl *FullModeDeploymentServiceImpl) GitOpsOperations(manifestResponse *be } func (impl *FullModeDeploymentServiceImpl) GenerateManifest(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, appStoreApplicationVersion *appStoreDiscoverRepository.AppStoreApplicationVersion) (manifestResponse *bean.AppStoreManifestResponse, err error) { - manifestResponse = &bean.AppStoreManifestResponse{} - - ChartCreateResponse, err := impl.createChartProxyAndGetPath(installAppVersionRequest) + values, dependencies, err := impl.getValuesAndRequirement(installAppVersionRequest, appStoreApplicationVersion) + if err != nil { + impl.Logger.Errorw("error in fetching values and requirements.yaml config while generating manifest", "err", err) + return manifestResponse, err + } + chartCreateRequest := adapter.ParseChartCreateRequest(installAppVersionRequest.AppName, dependencies, true) + chartCreateResponse, err := impl.createChartProxyAndGetPath(chartCreateRequest) if err != nil { impl.Logger.Errorw("Error in building chart while generating manifest", "err", err) return manifestResponse, err } - // valuesConfig and dependencyConfig's ChartConfig object contains ChartRepoName which is extracted from gitOpsRepoUrl + if chartCreateResponse != nil && chartCreateResponse.ChartMetaData == nil { + chartCreateResponse.ChartMetaData.Dependencies = dependencies + } + // valuesConfig and chartMetaDataConfig's ChartConfig object contains ChartRepoName which is extracted from gitOpsRepoUrl // that resides in the db and not from the current orchestrator cm prefix and appName. - valuesConfig, dependencyConfig, err := impl.getValuesAndRequirementForGitConfig(installAppVersionRequest, appStoreApplicationVersion) + valuesConfig, chartMetaDataConfig, err := impl.getValuesAndChartMetaDataForGitConfig(installAppVersionRequest, values, chartCreateResponse.ChartMetaData) if err != nil { - impl.Logger.Errorw("error in fetching values and requirements.yaml config while generating manifest", "err", err) + impl.Logger.Errorw("error in getting values and requirements config for git commit", "err", err) return manifestResponse, err } - - manifestResponse.ChartResponse = ChartCreateResponse + manifestResponse.ChartResponse = chartCreateResponse manifestResponse.ValuesConfig = valuesConfig - manifestResponse.RequirementsConfig = dependencyConfig - + manifestResponse.ChartMetaDataConfig = chartMetaDataConfig return manifestResponse, nil } @@ -109,7 +121,7 @@ func (impl *FullModeDeploymentServiceImpl) GenerateManifestAndPerformGitOperatio } func (impl *FullModeDeploymentServiceImpl) UpdateAppGitOpsOperations(manifest *bean.AppStoreManifestResponse, - installAppVersionRequest *appStoreBean.InstallAppVersionDTO, monoRepoMigrationRequired bool, commitRequirements bool) (*bean.AppStoreGitOpsResponse, error) { + installAppVersionRequest *appStoreBean.InstallAppVersionDTO, monoRepoMigrationRequired bool, updateDependencies bool) (*bean.AppStoreGitOpsResponse, error) { var requirementsCommitErr, valuesCommitErr error var gitHash string if monoRepoMigrationRequired { @@ -120,11 +132,20 @@ func (impl *FullModeDeploymentServiceImpl) UpdateAppGitOpsOperations(manifest *b gitOpsResponse := &bean.AppStoreGitOpsResponse{} ctx := context.Background() - if commitRequirements { + if updateDependencies { // update dependency if chart or chart version is changed - _, _, requirementsCommitErr = impl.gitOperationService.CommitValues(ctx, manifest.RequirementsConfig) + _, _, requirementsCommitErr = impl.gitOperationService.CommitValues(ctx, manifest.ChartMetaDataConfig) gitHash, _, valuesCommitErr = impl.gitOperationService.CommitValues(ctx, manifest.ValuesConfig) } else { + cloneChartToGitRequest := adapter.ParseChartGitPushRequest(installAppVersionRequest, "") + migrateDependencies, err := impl.shouldMigrateProxyChartDependencies(cloneChartToGitRequest) + if err != nil { + impl.Logger.Errorw("error in checking if proxy chart dependencies should be migrated", "err", err) + return nil, err + } + if migrateDependencies { + _, _, requirementsCommitErr = impl.gitOperationService.CommitValues(ctx, manifest.ChartMetaDataConfig) + } // only values are changed in update, so commit values config gitHash, _, valuesCommitErr = impl.gitOperationService.CommitValues(ctx, manifest.ValuesConfig) } @@ -184,20 +205,21 @@ func (impl *FullModeDeploymentServiceImpl) parseGitRepoErrorResponse(err error) } // createGitOpsRepoAndPushChart is a wrapper for creating GitOps repo and pushing chart to created repo -func (impl *FullModeDeploymentServiceImpl) createGitOpsRepoAndPushChart(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, builtChartPath string, requirementsConfig *git.ChartConfig, valuesConfig *git.ChartConfig) (*commonBean.ChartGitAttribute, string, error) { +func (impl *FullModeDeploymentServiceImpl) createGitOpsRepoAndPushChart(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, builtChartPath string, valuesConfig *git.ChartConfig) (*commonBean.ChartGitAttribute, string, error) { // in case of monorepo migration installAppVersionRequest.GitOpsRepoURL is "" if len(installAppVersionRequest.GitOpsRepoURL) == 0 { gitOpsConfigStatus, err := impl.gitOpsConfigReadService.GetGitOpsConfigActive() if err != nil { return nil, "", err } - InstalledApp, err := impl.installedAppRepository.GetInstalledApp(installAppVersionRequest.InstalledAppId) + installedApp, err := impl.installedAppRepository.GetInstalledApp(installAppVersionRequest.InstalledAppId) if err != nil { - impl.Logger.Errorw("service err, installedApp", "err", err) + impl.Logger.Errorw("service err, installedApp", "installedAppId", installAppVersionRequest.InstalledAppId, "err", err) return nil, "", err } - if gitOpsConfigStatus.AllowCustomRepository && InstalledApp.IsCustomRepository { - return nil, "", fmt.Errorf("Invalid request! Git repository URL is not found for installed app '%s'", installAppVersionRequest.AppName) + if gitOpsConfigStatus.AllowCustomRepository && installedApp.IsCustomRepository { + errMSg := fmt.Sprintf("Invalid request! Git repository URL is not found for installed app '%s'", installAppVersionRequest.AppName) + return nil, "", util.NewApiError(http.StatusBadRequest, errMSg, errMSg) } gitOpsRepoName := impl.gitOpsConfigReadService.GetGitOpsRepoName(installAppVersionRequest.AppName) gitOpsRepoURL, isNew, err := impl.createGitOpsRepo(gitOpsRepoName, installAppVersionRequest.GetTargetRevision(), installAppVersionRequest.UserId) @@ -211,7 +233,7 @@ func (impl *FullModeDeploymentServiceImpl) createGitOpsRepoAndPushChart(installA } pushChartToGitRequest := adapter.ParseChartGitPushRequest(installAppVersionRequest, builtChartPath) - chartGitAttribute, commitHash, err := impl.gitOperationService.PushChartToGitOpsRepoForHelmApp(context.Background(), pushChartToGitRequest, requirementsConfig, valuesConfig) + chartGitAttribute, commitHash, err := impl.gitOperationService.PushChartToGitOpsRepoForHelmApp(context.Background(), pushChartToGitRequest, valuesConfig) if err != nil { impl.Logger.Errorw("error in pushing chart to git", "err", err) return nil, "", err @@ -243,15 +265,13 @@ func (impl *FullModeDeploymentServiceImpl) createGitOpsRepo(gitOpsRepoName strin } // createChartProxyAndGetPath parse chart in local directory and returns path of local dir and values.yaml -func (impl *FullModeDeploymentServiceImpl) createChartProxyAndGetPath(installAppVersionRequest *appStoreBean.InstallAppVersionDTO) (*util.ChartCreateResponse, error) { - chartCreateRequest := adapter.ParseChartCreateRequest(installAppVersionRequest.AppName, true) +func (impl *FullModeDeploymentServiceImpl) createChartProxyAndGetPath(chartCreateRequest *util.ChartCreateRequest) (*util.ChartCreateResponse, error) { chartCreateResponse, err := impl.appStoreDeploymentCommonService.CreateChartProxyAndGetPath(chartCreateRequest) if err != nil { impl.Logger.Errorw("Error in building chart proxy", "err", err) return chartCreateResponse, err } return chartCreateResponse, nil - } // getGitCommitConfig will return util.ChartConfig (git commit config) for GitOps @@ -311,39 +331,53 @@ func (impl *FullModeDeploymentServiceImpl) getGitCommitConfig(installAppVersionR return YamlConfig, nil } -// getValuesAndRequirementForGitConfig will return chart values(*util.ChartConfig) and requirements(*util.ChartConfig) for git commit -func (impl *FullModeDeploymentServiceImpl) getValuesAndRequirementForGitConfig(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, appStoreAppVersion *appStoreDiscoverRepository.AppStoreApplicationVersion) (*git.ChartConfig, *git.ChartConfig, error) { - - var err error +// getValuesAndRequirement will return chart values(*git.ChartConfig) and requirements(*git.ChartConfig) for git commit +func (impl *FullModeDeploymentServiceImpl) getValuesAndRequirement(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, + appStoreAppVersion *appStoreDiscoverRepository.AppStoreApplicationVersion) (values map[string]map[string]any, dependencies []*chart.Dependency, err error) { if appStoreAppVersion == nil { appStoreAppVersion, err = impl.appStoreApplicationVersionRepository.FindById(installAppVersionRequest.AppStoreVersion) if err != nil { impl.Logger.Errorw("fetching error", "err", err) - return nil, nil, err + return values, dependencies, err } - } - values, err := impl.appStoreDeploymentCommonService.GetValuesString(appStoreAppVersion, installAppVersionRequest.ValuesOverrideYaml) + values, err = impl.appStoreDeploymentCommonService.GetProxyChartValues(appStoreAppVersion, installAppVersionRequest.ValuesOverrideYaml) if err != nil { impl.Logger.Errorw("error in getting values fot installedAppVersionRequest", "err", err) - return nil, nil, err + return values, dependencies, err + } + dependencies, err = impl.appStoreDeploymentCommonService.GetProxyChartRequirements(appStoreAppVersion) + if err != nil { + impl.Logger.Errorw("error in getting dependencies array fot installedAppVersionRequest", "err", err) + return values, dependencies, err } - dependency, err := impl.appStoreDeploymentCommonService.GetRequirementsString(appStoreAppVersion) + return values, dependencies, err +} + +// getValuesAndChartMetaDataForGitConfig will return chart values(*git.ChartConfig) and requirements(*git.ChartConfig) for git commit +func (impl *FullModeDeploymentServiceImpl) getValuesAndChartMetaDataForGitConfig(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, + values map[string]map[string]any, chartMetaData *chart.Metadata) (*git.ChartConfig, *git.ChartConfig, error) { + valuesContent, err := json.Marshal(values) if err != nil { - impl.Logger.Errorw("error in getting dependency array fot installedAppVersionRequest", "err", err) + impl.Logger.Errorw("error in marshalling values content", "err", err) return nil, nil, err } - valuesConfig, err := impl.getGitCommitConfig(installAppVersionRequest, values, appStoreBean.VALUES_YAML_FILE) + valuesConfig, err := impl.getGitCommitConfig(installAppVersionRequest, string(valuesContent), appStoreBean.VALUES_YAML_FILE) if err != nil { impl.Logger.Errorw("error in creating values config for git", "err", err) return nil, nil, err } - RequirementConfig, err := impl.getGitCommitConfig(installAppVersionRequest, dependency, appStoreBean.REQUIREMENTS_YAML_FILE) + chartMetaDataContent, err := json.Marshal(chartMetaData) + if err != nil { + impl.Logger.Errorw("error in marshalling chartMetaData content", "err", err) + return nil, nil, err + } + chartMetaDataConfig, err := impl.getGitCommitConfig(installAppVersionRequest, string(chartMetaDataContent), chartRefBean.CHART_YAML_FILE) if err != nil { impl.Logger.Errorw("error in creating dependency config for git", "err", err) return nil, nil, err } - return valuesConfig, RequirementConfig, nil + return valuesConfig, chartMetaDataConfig, nil } func (impl *FullModeDeploymentServiceImpl) ValidateCustomGitOpsConfig(request validationBean.ValidateGitOpsRepoRequest) (string, bool, error) { @@ -377,3 +411,72 @@ func (impl *FullModeDeploymentServiceImpl) CreateArgoRepoSecretIfNeeded(appStore } return nil } + +func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(pushChartToGitRequest *gitBean.PushChartToGitRequestDTO) (bool, error) { + clonedDir, err := impl.gitOperationService.CloneChartForHelmApp(pushChartToGitRequest.AppName, pushChartToGitRequest.RepoURL, pushChartToGitRequest.TargetRevision) + if err != nil { + impl.Logger.Errorw("error in cloning chart for helm app", "appName", pushChartToGitRequest.AppName, "repoUrl", pushChartToGitRequest.RepoURL, "err", err) + return false, err + } + defer impl.chartTemplateService.CleanDir(clonedDir) + gitOpsChartLocation := fmt.Sprintf("%s-%s", pushChartToGitRequest.AppName, pushChartToGitRequest.EnvName) + dir := filepath.Join(clonedDir, gitOpsChartLocation) + requirementsYamlPath := filepath.Join(dir, appStoreBean.REQUIREMENTS_YAML_FILE) + if _, err := os.Stat(requirementsYamlPath); os.IsNotExist(err) { + impl.Logger.Debugw("requirements.yaml not found in cloned repo from git-ops, no migrations required", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName) + return false, nil + } else if err != nil { + impl.Logger.Errorw("error in checking requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) + return false, err + } + chartYamlPath := filepath.Join(dir, chartRefBean.CHART_YAML_FILE) + if _, err := os.Stat(chartYamlPath); os.IsNotExist(err) { + impl.Logger.Debugw("chart.yaml not found in cloned repo from git-ops, no migrations required", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName) + return false, nil + } else if err != nil { + impl.Logger.Errorw("error in checking chart.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) + return false, err + } + // load requirements.yaml file to check if it has dependencies + requirementsYamlContent, err := os.ReadFile(requirementsYamlPath) + if err != nil { + impl.Logger.Errorw("error in reading requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) + return false, err + } + dependencies := appStoreBean.Dependencies{} + err = json.Unmarshal(requirementsYamlContent, &dependencies) + if err != nil { + impl.Logger.Errorw("error in unmarshalling requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) + return false, err + } + if len(dependencies.Dependencies) == 0 { + impl.Logger.Debugw("no dependencies found in requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName) + return false, nil + } + impl.Logger.Debugw("dependencies found in requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "dependencies", dependencies.Dependencies) + // check if chart.yaml file has dependencies + chartYamlContent, err := os.ReadFile(chartYamlPath) + if err != nil { + impl.Logger.Errorw("error in reading chart.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) + return false, err + } + chartMetadata := &chart.Metadata{} + err = json.Unmarshal(chartYamlContent, chartMetadata) + if err != nil { + impl.Logger.Errorw("error in unmarshalling chart.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) + return false, err + } + if len(chartMetadata.Dependencies) == 0 { + impl.Logger.Debugw("no dependencies found in chart.yaml file, need to migrate proxy chart dependencies", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName) + return true, nil + } + impl.Logger.Debugw("dependencies found in chart.yaml file, validating against requirements.yaml", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "chartDependencies", chartMetadata.Dependencies) + // validate if chart.yaml dependencies are present in requirements.yaml + latestDependencies := sliceUtil.NewSliceFromFuncExec(chartMetadata.Dependencies, func(dependency *chart.Dependency) string { + return fmt.Sprintf("%s-%s-%s", strings.TrimSpace(dependency.Name), strings.TrimSpace(dependency.Version), strings.TrimSpace(dependency.Repository)) + }) + previousDependencies := sliceUtil.NewSliceFromFuncExec(dependencies.Dependencies, func(dependency *chart.Dependency) string { + return fmt.Sprintf("%s-%s-%s", strings.TrimSpace(dependency.Name), strings.TrimSpace(dependency.Version), strings.TrimSpace(dependency.Repository)) + }) + return sliceUtil.CompareTwoSlices(latestDependencies, previousDependencies), nil +} diff --git a/pkg/appStore/installedApp/service/bean/bean.go b/pkg/appStore/installedApp/service/bean/bean.go index 7120082b32..e8a095de78 100644 --- a/pkg/appStore/installedApp/service/bean/bean.go +++ b/pkg/appStore/installedApp/service/bean/bean.go @@ -23,9 +23,9 @@ import ( ) type AppStoreManifestResponse struct { - ChartResponse *util.ChartCreateResponse - ValuesConfig *git.ChartConfig - RequirementsConfig *git.ChartConfig + ChartResponse *util.ChartCreateResponse + ValuesConfig *git.ChartConfig + ChartMetaDataConfig *git.ChartConfig } type AppStoreGitOpsResponse struct { diff --git a/pkg/appStore/installedApp/service/common/AppStoreDeploymentCommonService.go b/pkg/appStore/installedApp/service/common/AppStoreDeploymentCommonService.go index 023c6be828..f414488c6d 100644 --- a/pkg/appStore/installedApp/service/common/AppStoreDeploymentCommonService.go +++ b/pkg/appStore/installedApp/service/common/AppStoreDeploymentCommonService.go @@ -36,6 +36,7 @@ import ( "github.com/go-pg/pg" "go.opentelemetry.io/otel" "go.uber.org/zap" + "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" "k8s.io/utils/pointer" "net/http" @@ -47,9 +48,9 @@ import ( type AppStoreDeploymentCommonService interface { // GetValuesString will return values string from the given valuesOverrideYaml - GetValuesString(appStoreApplicationVersion *appStoreDiscoverRepository.AppStoreApplicationVersion, valuesOverrideYaml string) (string, error) - // GetRequirementsString will return requirement dependencies for the given appStoreVersionId - GetRequirementsString(appStoreApplicationVersion *appStoreDiscoverRepository.AppStoreApplicationVersion) (string, error) + GetProxyChartValues(appStoreAppVersion *appStoreDiscoverRepository.AppStoreApplicationVersion, valuesOverrideYaml string) (valuesMap map[string]map[string]any, err error) + // GetProxyChartRequirements will return requirement dependencies for the given appStoreVersionId + GetProxyChartRequirements(appStoreAppVersion *appStoreDiscoverRepository.AppStoreApplicationVersion) (dependencies []*chart.Dependency, err error) // CreateChartProxyAndGetPath parse chart in local directory and returns path of local dir and values.yaml CreateChartProxyAndGetPath(chartCreateRequest *util.ChartCreateRequest) (*util.ChartCreateResponse, error) GetDeploymentHistoryFromDB(ctx context.Context, installedApp *appStoreBean.InstallAppVersionDTO) (*gRPC.HelmAppDeploymentHistory, error) @@ -169,28 +170,22 @@ func (impl *AppStoreDeploymentCommonServiceImpl) GetDeploymentHistoryInfoFromDB( return values, err } -func (impl AppStoreDeploymentCommonServiceImpl) GetValuesString(appStoreApplicationVersion *appStoreDiscoverRepository.AppStoreApplicationVersion, valuesOverrideYaml string) (string, error) { - - ValuesOverrideByte, err := yaml.YAMLToJSON([]byte(valuesOverrideYaml)) +func (impl *AppStoreDeploymentCommonServiceImpl) GetProxyChartValues(appStoreAppVersion *appStoreDiscoverRepository.AppStoreApplicationVersion, valuesOverrideYaml string) (valuesMap map[string]map[string]any, err error) { + valuesMap = make(map[string]map[string]any) + valuesOverrideByte, err := yaml.YAMLToJSON([]byte(valuesOverrideYaml)) if err != nil { - impl.logger.Errorw("") + impl.logger.Errorw("error in converting values override yaml to json", "err", err) + return valuesMap, err } - - var dat map[string]interface{} - err = json.Unmarshal(ValuesOverrideByte, &dat) + var dat map[string]any + err = json.Unmarshal(valuesOverrideByte, &dat) if err != nil { impl.logger.Errorw("error in unmarshalling values override byte", "err", err) - return "", err + return valuesMap, err } - - valuesMap := make(map[string]map[string]interface{}) - valuesMap[GetChartNameFromAppStoreApplicationVersion(appStoreApplicationVersion)] = dat - valuesByte, err := json.Marshal(valuesMap) - if err != nil { - impl.logger.Errorw("error in marshaling", "err", err) - return "", err - } - return string(valuesByte), nil + chartName := GetChartNameFromAppStoreApplicationVersion(appStoreAppVersion) + valuesMap[chartName] = dat + return valuesMap, nil } func GetChartNameFromAppStoreApplicationVersion(appStoreApplicationVersion *appStoreDiscoverRepository.AppStoreApplicationVersion) string { @@ -201,9 +196,8 @@ func GetChartNameFromAppStoreApplicationVersion(appStoreApplicationVersion *appS } } -func (impl AppStoreDeploymentCommonServiceImpl) GetRequirementsString(appStoreAppVersion *appStoreDiscoverRepository.AppStoreApplicationVersion) (string, error) { - - dependency := appStoreBean.Dependency{ +func (impl *AppStoreDeploymentCommonServiceImpl) GetProxyChartRequirements(appStoreAppVersion *appStoreDiscoverRepository.AppStoreApplicationVersion) (dependencies []*chart.Dependency, err error) { + dependency := &chart.Dependency{ Name: GetChartNameFromAppStoreApplicationVersion(appStoreAppVersion), Version: appStoreAppVersion.Version, } @@ -213,25 +207,13 @@ func (impl AppStoreDeploymentCommonServiceImpl) GetRequirementsString(appStoreAp repositoryURL, repositoryName, err := sanitizeRepoNameAndURLForOCIRepo(appStoreAppVersion.AppStore.DockerArtifactStore.RegistryURL, appStoreAppVersion.AppStore.Name) if err != nil { impl.logger.Errorw("error in getting sanitized repository name and url", "repositoryURL", repositoryURL, "repositoryName", repositoryName, "err", err) - return "", err + return dependencies, err } dependency.Repository = repositoryURL } - var dependencies []appStoreBean.Dependency dependencies = append(dependencies, dependency) - requirementDependencies := &appStoreBean.Dependencies{ - Dependencies: dependencies, - } - requirementDependenciesByte, err := json.Marshal(requirementDependencies) - if err != nil { - return "", err - } - requirementDependenciesByte, err = yaml.JSONToYAML(requirementDependenciesByte) - if err != nil { - return "", err - } - return string(requirementDependenciesByte), nil + return dependencies, nil } func sanitizeRepoNameAndURLForOCIRepo(repositoryURL, repositoryName string) (string, string, error) { @@ -262,14 +244,17 @@ func sanitizeRepoNameAndURLForOCIRepo(repositoryURL, repositoryName string) (str return repositoryURL, repositoryName, nil } -func (impl AppStoreDeploymentCommonServiceImpl) CreateChartProxyAndGetPath(chartCreateRequest *util.ChartCreateRequest) (*util.ChartCreateResponse, error) { - ChartCreateResponse := &util.ChartCreateResponse{} +func (impl *AppStoreDeploymentCommonServiceImpl) CreateChartProxyAndGetPath(chartCreateRequest *util.ChartCreateRequest) (*util.ChartCreateResponse, error) { + chartCreateResponse := &util.ChartCreateResponse{} valid, err := chartutil.IsChartDir(chartCreateRequest.ChartPath) - if err != nil || !valid { - impl.logger.Errorw("invalid base chart", "dir", chartCreateRequest.ChartPath, "err", err) - return ChartCreateResponse, err + if err != nil { + impl.logger.Errorw("error in checking if chart path is valid", "dir", chartCreateRequest.ChartPath, "err", err) + return chartCreateResponse, err + } else if !valid { + impl.logger.Errorw("invalid base chart", "dir", chartCreateRequest.ChartPath) + return chartCreateResponse, err } - chartCreateResponse, err := impl.chartTemplateService.BuildChartProxyForHelmApps(chartCreateRequest) + chartCreateResponse, err = impl.chartTemplateService.BuildChartProxyForHelmApps(chartCreateRequest) if err != nil { impl.logger.Errorw("Error in building chart proxy", "err", err) return chartCreateResponse, err diff --git a/pkg/deployment/gitOps/git/GitOperationService.go b/pkg/deployment/gitOps/git/GitOperationService.go index fdb561d32f..f2c82459e5 100644 --- a/pkg/deployment/gitOps/git/GitOperationService.go +++ b/pkg/deployment/gitOps/git/GitOperationService.go @@ -27,6 +27,7 @@ import ( commonBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/common/bean" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" + chartRefBean "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" globalUtil "github.com/devtron-labs/devtron/util" dirCopy "github.com/otiai10/copy" "go.opentelemetry.io/otel" @@ -49,7 +50,8 @@ type GitOperationService interface { CommitValues(ctx context.Context, chartGitAttr *ChartConfig) (commitHash string, commitTime time.Time, err error) PushChartToGitRepo(ctx context.Context, gitOpsRepoName, chartLocation, tempReferenceTemplateDir, repoUrl, targetRevision string, userId int32) (err error) - PushChartToGitOpsRepoForHelmApp(ctx context.Context, pushChartToGitRequest *bean.PushChartToGitRequestDTO, requirementsConfig, valuesConfig *ChartConfig) (*commonBean.ChartGitAttribute, string, error) + CloneChartForHelmApp(helmAppName, gitRepoUrl, targetRevision string) (string, error) + PushChartToGitOpsRepoForHelmApp(ctx context.Context, pushChartToGitRequest *bean.PushChartToGitRequestDTO, valuesConfig *ChartConfig) (*commonBean.ChartGitAttribute, string, error) CreateRepository(ctx context.Context, dto *apiBean.GitOpsConfigDto, userId int32) (string, bool, bool, error) @@ -151,7 +153,7 @@ func (impl *GitOperationServiceImpl) PushChartToGitRepo(ctx context.Context, git // auto-healing : data corruption fix - sometimes reference chart contents are not pushed in git-ops repo. // copying content from reference template dir to cloned dir (if Chart.yaml file is not found) // if Chart.yaml file is not found, we are assuming here that reference chart contents are not pushed in git-ops repo - if _, err := os.Stat(filepath.Join(dir, "Chart.yaml")); os.IsNotExist(err) { + if _, err := os.Stat(filepath.Join(dir, chartRefBean.CHART_YAML_FILE)); os.IsNotExist(err) { impl.logger.Infow("auto-healing: Chart.yaml not found in cloned repo from git-ops. copying content", "from", tempReferenceTemplateDir, "to", dir) err = dirCopy.Copy(tempReferenceTemplateDir, dir) if err != nil { @@ -303,26 +305,36 @@ func (impl *GitOperationServiceImpl) CreateRepository(ctx context.Context, dto * return repoUrl, isNew, isEmpty, nil } -// PushChartToGitOpsRepoForHelmApp pushes built chart to GitOps repo (Specific implementation for Helm Apps) -// TODO refactoring: Make a common method for both PushChartToGitRepo and PushChartToGitOpsRepoForHelmApp -func (impl *GitOperationServiceImpl) PushChartToGitOpsRepoForHelmApp(ctx context.Context, pushChartToGitRequest *bean.PushChartToGitRequestDTO, requirementsConfig, valuesConfig *ChartConfig) (*commonBean.ChartGitAttribute, string, error) { - chartDir := fmt.Sprintf("%s-%s", pushChartToGitRequest.AppName, impl.chartTemplateService.GetDir()) +func (impl *GitOperationServiceImpl) CloneChartForHelmApp(helmAppName, gitRepoUrl, targetRevision string) (string, error) { + chartDir := fmt.Sprintf("%s-%s", helmAppName, impl.chartTemplateService.GetDir()) clonedDir := impl.gitFactory.GitOpsHelper.GetCloneDirectory(chartDir) if _, err := os.Stat(clonedDir); os.IsNotExist(err) { - clonedDir, err = impl.gitFactory.GitOpsHelper.Clone(pushChartToGitRequest.RepoURL, chartDir, pushChartToGitRequest.TargetRevision) + clonedDir, err = impl.gitFactory.GitOpsHelper.Clone(gitRepoUrl, chartDir, targetRevision) if err != nil { - impl.logger.Errorw("error in cloning repo", "url", pushChartToGitRequest.RepoURL, "err", err) - return nil, "", err + impl.logger.Errorw("error in cloning repo", "url", targetRevision, "err", err) + return clonedDir, err } } else { - err = impl.GitPull(clonedDir, pushChartToGitRequest.RepoURL, pushChartToGitRequest.TargetRevision) + err = impl.GitPull(clonedDir, gitRepoUrl, targetRevision) if err != nil { - return nil, "", err + return clonedDir, err } } + return clonedDir, nil +} + +// PushChartToGitOpsRepoForHelmApp pushes built chart to GitOps repo (Specific implementation for Helm Apps) +// TODO refactoring: Make a common method for both PushChartToGitRepo and PushChartToGitOpsRepoForHelmApp +func (impl *GitOperationServiceImpl) PushChartToGitOpsRepoForHelmApp(ctx context.Context, pushChartToGitRequest *bean.PushChartToGitRequestDTO, valuesConfig *ChartConfig) (*commonBean.ChartGitAttribute, string, error) { + clonedDir, err := impl.CloneChartForHelmApp(pushChartToGitRequest.AppName, pushChartToGitRequest.RepoURL, pushChartToGitRequest.TargetRevision) + if err != nil { + impl.logger.Errorw("error in cloning chart for helm app", "appName", pushChartToGitRequest.AppName, "repoUrl", pushChartToGitRequest.RepoURL, "err", err) + return nil, "", err + } + defer impl.chartTemplateService.CleanDir(clonedDir) gitOpsChartLocation := fmt.Sprintf("%s-%s", pushChartToGitRequest.AppName, pushChartToGitRequest.EnvName) dir := filepath.Join(clonedDir, gitOpsChartLocation) - err := os.MkdirAll(dir, os.ModePerm) + err = os.MkdirAll(dir, os.ModePerm) if err != nil { impl.logger.Errorw("error in making dir", "err", err) return nil, "", err @@ -332,11 +344,6 @@ func (impl *GitOperationServiceImpl) PushChartToGitOpsRepoForHelmApp(ctx context impl.logger.Errorw("error copying dir", "err", err) return nil, "", err } - err = impl.addConfigFileToChart(requirementsConfig, dir, clonedDir) - if err != nil { - impl.logger.Errorw("error in adding requirements.yaml to chart", "appName", pushChartToGitRequest.AppName, "err", err) - return nil, "", err - } err = impl.addConfigFileToChart(valuesConfig, dir, clonedDir) if err != nil { impl.logger.Errorw("error in adding values.yaml to chart", "appName", pushChartToGitRequest.AppName, "err", err) @@ -364,7 +371,6 @@ func (impl *GitOperationServiceImpl) PushChartToGitOpsRepoForHelmApp(ctx context } } impl.logger.Debugw("template committed", "url", pushChartToGitRequest.RepoURL, "commit", commit) - defer impl.chartTemplateService.CleanDir(clonedDir) return &commonBean.ChartGitAttribute{ RepoUrl: pushChartToGitRequest.RepoURL, ChartLocation: gitOpsChartLocation, diff --git a/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartRefService.go b/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartRefService.go index d61d17ffe1..1432511f87 100644 --- a/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartRefService.go +++ b/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartRefService.go @@ -659,7 +659,7 @@ func (impl *ChartRefServiceImpl) ExtractChartIfMissing(chartData []byte, refChar func (impl *ChartRefServiceImpl) readChartMetaDataForLocation(chartDir string, fileName string) (*bean.ChartYamlStruct, error) { chartLocation := filepath.Clean(filepath.Join(chartDir, fileName)) - chartYamlPath := filepath.Clean(filepath.Join(chartLocation, "Chart.yaml")) + chartYamlPath := filepath.Clean(filepath.Join(chartLocation, bean.CHART_YAML_FILE)) if _, err := os.Stat(chartYamlPath); os.IsNotExist(err) { return nil, fmt.Errorf("Chart.yaml file not present in the directory") } diff --git a/pkg/deployment/manifest/deploymentTemplate/chartRef/bean/bean.go b/pkg/deployment/manifest/deploymentTemplate/chartRef/bean/bean.go index 68b8518146..cc91e4ef62 100644 --- a/pkg/deployment/manifest/deploymentTemplate/chartRef/bean/bean.go +++ b/pkg/deployment/manifest/deploymentTemplate/chartRef/bean/bean.go @@ -142,3 +142,5 @@ type PipelineStrategy struct { Config json.RawMessage `json:"config"` Default bool `json:"default"` } + +var CHART_YAML_FILE = "Chart.yaml" From 1dbb0ed3579984064ec13d2e10b00bc4bc7c03e0 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Tue, 29 Jul 2025 09:02:29 +0530 Subject: [PATCH 02/10] refactor: improve chart metadata handling and error logging in GitOps operations --- .../deployment/InstalledAppGitOpsService.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index 5daf1fc26f..f5cdca77f0 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -87,12 +87,16 @@ func (impl *FullModeDeploymentServiceImpl) GenerateManifest(installAppVersionReq impl.Logger.Errorw("Error in building chart while generating manifest", "err", err) return manifestResponse, err } - if chartCreateResponse != nil && chartCreateResponse.ChartMetaData == nil { - chartCreateResponse.ChartMetaData.Dependencies = dependencies + var chartMetaData *chart.Metadata + if chartCreateResponse != nil { + if chartCreateResponse.ChartMetaData != nil { + chartCreateResponse.ChartMetaData.Dependencies = dependencies + } + chartMetaData = chartCreateResponse.ChartMetaData } // valuesConfig and chartMetaDataConfig's ChartConfig object contains ChartRepoName which is extracted from gitOpsRepoUrl // that resides in the db and not from the current orchestrator cm prefix and appName. - valuesConfig, chartMetaDataConfig, err := impl.getValuesAndChartMetaDataForGitConfig(installAppVersionRequest, values, chartCreateResponse.ChartMetaData) + valuesConfig, chartMetaDataConfig, err := impl.getValuesAndChartMetaDataForGitConfig(installAppVersionRequest, values, chartMetaData) if err != nil { impl.Logger.Errorw("error in getting values and requirements config for git commit", "err", err) return manifestResponse, err @@ -357,6 +361,11 @@ func (impl *FullModeDeploymentServiceImpl) getValuesAndRequirement(installAppVer // getValuesAndChartMetaDataForGitConfig will return chart values(*git.ChartConfig) and requirements(*git.ChartConfig) for git commit func (impl *FullModeDeploymentServiceImpl) getValuesAndChartMetaDataForGitConfig(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, values map[string]map[string]any, chartMetaData *chart.Metadata) (*git.ChartConfig, *git.ChartConfig, error) { + if chartMetaData == nil || values == nil { + err := fmt.Errorf("chartMetaData or values cannot be nil") + impl.Logger.Errorw("error in getting chartMetaData or values for git commit", "err", err) + return nil, nil, err + } valuesContent, err := json.Marshal(values) if err != nil { impl.Logger.Errorw("error in marshalling values content", "err", err) From cbd83e52e71272319737e86f5e1aa6f80b07d9d2 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Tue, 29 Jul 2025 17:06:36 +0530 Subject: [PATCH 03/10] refactor: add support for setting APIVersion in chart metadata --- internal/util/ChartTemplateService.go | 3 +++ .../reference-chart-proxy/requirements.yaml | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 scripts/devtron-reference-helm-charts/reference-chart-proxy/requirements.yaml diff --git a/internal/util/ChartTemplateService.go b/internal/util/ChartTemplateService.go index 8eb4e76819..317a26d66b 100644 --- a/internal/util/ChartTemplateService.go +++ b/internal/util/ChartTemplateService.go @@ -292,6 +292,9 @@ func (impl ChartTemplateServiceImpl) overrideChartMetaDataInDir(chartDir string, impl.logger.Errorw("error in loading template chart", "chartPath", chartDir, "err", err) return nil, err } + if len(chartMetaData.APIVersion) > 0 { + chart.Metadata.APIVersion = chartMetaData.APIVersion + } if len(chartMetaData.Name) > 0 { chart.Metadata.Name = chartMetaData.Name } diff --git a/scripts/devtron-reference-helm-charts/reference-chart-proxy/requirements.yaml b/scripts/devtron-reference-helm-charts/reference-chart-proxy/requirements.yaml deleted file mode 100644 index 8b22f76a34..0000000000 --- a/scripts/devtron-reference-helm-charts/reference-chart-proxy/requirements.yaml +++ /dev/null @@ -1,4 +0,0 @@ -dependencies: -- name: sample - version: 0.0.0 - repository: sample-url From ccfbd20714b242135be104d7ef120d530ce735ca Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 30 Jul 2025 17:04:40 +0530 Subject: [PATCH 04/10] refactor: convert requirements.yaml to JSON before unmarshalling in GitOps operations --- .../FullMode/deployment/InstalledAppGitOpsService.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index f5cdca77f0..22949f5b96 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -40,6 +40,7 @@ import ( "net/http" "os" "path/filepath" + "sigs.k8s.io/yaml" "strconv" "strings" ) @@ -453,7 +454,12 @@ func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(p return false, err } dependencies := appStoreBean.Dependencies{} - err = json.Unmarshal(requirementsYamlContent, &dependencies) + requirementsJsonContent, err := yaml.YAMLToJSON(requirementsYamlContent) + if err != nil { + impl.Logger.Errorw("error in converting requirements.yaml to json", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) + return false, err + } + err = json.Unmarshal(requirementsJsonContent, &dependencies) if err != nil { impl.Logger.Errorw("error in unmarshalling requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) return false, err From f875ca0800875a77b87c9f8450a94d0dff894cf8 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 30 Jul 2025 17:32:12 +0530 Subject: [PATCH 05/10] refactor: convert chart.yaml to JSON before unmarshalling in GitOps operations --- .../FullMode/deployment/InstalledAppGitOpsService.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index 22949f5b96..d5686f53cf 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -476,7 +476,12 @@ func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(p return false, err } chartMetadata := &chart.Metadata{} - err = json.Unmarshal(chartYamlContent, chartMetadata) + chartJsonContent, err := yaml.YAMLToJSON(chartYamlContent) + if err != nil { + impl.Logger.Errorw("error in converting chart.yaml to json", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) + return false, err + } + err = json.Unmarshal(chartJsonContent, chartMetadata) if err != nil { impl.Logger.Errorw("error in unmarshalling chart.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) return false, err From 92715dc71abd4ff186672e116b396db88f341a8f Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Thu, 31 Jul 2025 01:36:17 +0530 Subject: [PATCH 06/10] refactor: enhance dependency validation by using unique keys for comparison in GitOps operations --- .../deployment/InstalledAppGitOpsService.go | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index d5686f53cf..ff26e879f8 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -492,11 +492,26 @@ func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(p } impl.Logger.Debugw("dependencies found in chart.yaml file, validating against requirements.yaml", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "chartDependencies", chartMetadata.Dependencies) // validate if chart.yaml dependencies are present in requirements.yaml - latestDependencies := sliceUtil.NewSliceFromFuncExec(chartMetadata.Dependencies, func(dependency *chart.Dependency) string { - return fmt.Sprintf("%s-%s-%s", strings.TrimSpace(dependency.Name), strings.TrimSpace(dependency.Version), strings.TrimSpace(dependency.Repository)) + latestDependencies := sliceUtil.NewMapFromFuncExec(chartMetadata.Dependencies, func(dependency *chart.Dependency) string { + return getUniqueKeyFromDependency(dependency) }) - previousDependencies := sliceUtil.NewSliceFromFuncExec(dependencies.Dependencies, func(dependency *chart.Dependency) string { - return fmt.Sprintf("%s-%s-%s", strings.TrimSpace(dependency.Name), strings.TrimSpace(dependency.Version), strings.TrimSpace(dependency.Repository)) + previousDependencies := sliceUtil.NewMapFromFuncExec(dependencies.Dependencies, func(dependency *chart.Dependency) string { + return getUniqueKeyFromDependency(dependency) }) - return sliceUtil.CompareTwoSlices(latestDependencies, previousDependencies), nil + for key := range latestDependencies { + if _, ok := previousDependencies[key]; !ok { + impl.Logger.Debugw("dependency found in chart.yaml but not in requirements.yaml, need to migrate proxy chart dependencies", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "dependency", key) + return true, nil + } + } + impl.Logger.Debugw("all dependencies found in chart.yaml and requirements.yaml, no migration required", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName) + return false, nil +} + +func getUniqueKeyFromDependency(dependency *chart.Dependency) string { + // return unique key for dependency + return fmt.Sprintf("%s-%s-%s", + strings.ToLower(strings.TrimSpace(dependency.Name)), + strings.ToLower(strings.TrimSpace(dependency.Version)), + strings.ToLower(strings.TrimSpace(dependency.Repository))) } From 829bae2b7f3ce7c3ff64c29c75115e37ec37bfa0 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Thu, 31 Jul 2025 01:43:42 +0530 Subject: [PATCH 07/10] refactor: convert chart metadata from JSON to YAML format for GitOps operations --- .../FullMode/deployment/InstalledAppGitOpsService.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index ff26e879f8..1d2b5e5f53 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -377,12 +377,17 @@ func (impl *FullModeDeploymentServiceImpl) getValuesAndChartMetaDataForGitConfig impl.Logger.Errorw("error in creating values config for git", "err", err) return nil, nil, err } - chartMetaDataContent, err := json.Marshal(chartMetaData) + chartMetaJsonContent, err := json.Marshal(chartMetaData) if err != nil { impl.Logger.Errorw("error in marshalling chartMetaData content", "err", err) return nil, nil, err } - chartMetaDataConfig, err := impl.getGitCommitConfig(installAppVersionRequest, string(chartMetaDataContent), chartRefBean.CHART_YAML_FILE) + chartMetaYamlContent, err := yaml.JSONToYAML(chartMetaJsonContent) + if err != nil { + impl.Logger.Errorw("error in converting chartMetaData json to yaml", "err", err) + return nil, nil, err + } + chartMetaDataConfig, err := impl.getGitCommitConfig(installAppVersionRequest, string(chartMetaYamlContent), chartRefBean.CHART_YAML_FILE) if err != nil { impl.Logger.Errorw("error in creating dependency config for git", "err", err) return nil, nil, err From fba19a03daa8c3bc9f2a341d5e4460ea0d9daf75 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Thu, 31 Jul 2025 16:55:33 +0530 Subject: [PATCH 08/10] refactor: update shouldMigrateProxyChartDependencies to accept expected chart metadata and remove requirements.yaml checks --- pkg/appStore/bean/bean.go | 5 ---- .../deployment/InstalledAppGitOpsService.go | 30 +++++-------------- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/pkg/appStore/bean/bean.go b/pkg/appStore/bean/bean.go index 601b146cc0..84dfdd3bfd 100644 --- a/pkg/appStore/bean/bean.go +++ b/pkg/appStore/bean/bean.go @@ -31,7 +31,6 @@ import ( "github.com/devtron-labs/devtron/pkg/cluster/environment/bean" bean2 "github.com/devtron-labs/devtron/pkg/deployment/common/bean" "github.com/devtron-labs/devtron/util" - "helm.sh/helm/v3/pkg/chart" "slices" "time" ) @@ -336,10 +335,6 @@ type AppNames struct { SuggestedName string `json:"suggestedName,omitempty"` } -type Dependencies struct { - Dependencies []*chart.Dependency `json:"dependencies"` -} - const REFERENCE_TYPE_DEFAULT string = "DEFAULT" const REFERENCE_TYPE_TEMPLATE string = "TEMPLATE" const REFERENCE_TYPE_DEPLOYED string = "DEPLOYED" diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index 1d2b5e5f53..159739901f 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -143,7 +143,7 @@ func (impl *FullModeDeploymentServiceImpl) UpdateAppGitOpsOperations(manifest *b gitHash, _, valuesCommitErr = impl.gitOperationService.CommitValues(ctx, manifest.ValuesConfig) } else { cloneChartToGitRequest := adapter.ParseChartGitPushRequest(installAppVersionRequest, "") - migrateDependencies, err := impl.shouldMigrateProxyChartDependencies(cloneChartToGitRequest) + migrateDependencies, err := impl.shouldMigrateProxyChartDependencies(cloneChartToGitRequest, manifest.ChartMetaDataConfig.FileContent) if err != nil { impl.Logger.Errorw("error in checking if proxy chart dependencies should be migrated", "err", err) return nil, err @@ -427,7 +427,7 @@ func (impl *FullModeDeploymentServiceImpl) CreateArgoRepoSecretIfNeeded(appStore return nil } -func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(pushChartToGitRequest *gitBean.PushChartToGitRequestDTO) (bool, error) { +func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(pushChartToGitRequest *gitBean.PushChartToGitRequestDTO, expectedChartYamlContent string) (bool, error) { clonedDir, err := impl.gitOperationService.CloneChartForHelmApp(pushChartToGitRequest.AppName, pushChartToGitRequest.RepoURL, pushChartToGitRequest.TargetRevision) if err != nil { impl.Logger.Errorw("error in cloning chart for helm app", "appName", pushChartToGitRequest.AppName, "repoUrl", pushChartToGitRequest.RepoURL, "err", err) @@ -436,14 +436,6 @@ func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(p defer impl.chartTemplateService.CleanDir(clonedDir) gitOpsChartLocation := fmt.Sprintf("%s-%s", pushChartToGitRequest.AppName, pushChartToGitRequest.EnvName) dir := filepath.Join(clonedDir, gitOpsChartLocation) - requirementsYamlPath := filepath.Join(dir, appStoreBean.REQUIREMENTS_YAML_FILE) - if _, err := os.Stat(requirementsYamlPath); os.IsNotExist(err) { - impl.Logger.Debugw("requirements.yaml not found in cloned repo from git-ops, no migrations required", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName) - return false, nil - } else if err != nil { - impl.Logger.Errorw("error in checking requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) - return false, err - } chartYamlPath := filepath.Join(dir, chartRefBean.CHART_YAML_FILE) if _, err := os.Stat(chartYamlPath); os.IsNotExist(err) { impl.Logger.Debugw("chart.yaml not found in cloned repo from git-ops, no migrations required", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName) @@ -452,28 +444,22 @@ func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(p impl.Logger.Errorw("error in checking chart.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) return false, err } - // load requirements.yaml file to check if it has dependencies - requirementsYamlContent, err := os.ReadFile(requirementsYamlPath) - if err != nil { - impl.Logger.Errorw("error in reading requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) - return false, err - } - dependencies := appStoreBean.Dependencies{} - requirementsJsonContent, err := yaml.YAMLToJSON(requirementsYamlContent) + expectedChartMetaData := &chart.Metadata{} + expectedChartJsonContent, err := yaml.YAMLToJSON([]byte(expectedChartYamlContent)) if err != nil { impl.Logger.Errorw("error in converting requirements.yaml to json", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) return false, err } - err = json.Unmarshal(requirementsJsonContent, &dependencies) + err = json.Unmarshal(expectedChartJsonContent, &expectedChartMetaData) if err != nil { impl.Logger.Errorw("error in unmarshalling requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "err", err) return false, err } - if len(dependencies.Dependencies) == 0 { + if len(expectedChartMetaData.Dependencies) == 0 { impl.Logger.Debugw("no dependencies found in requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName) return false, nil } - impl.Logger.Debugw("dependencies found in requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "dependencies", dependencies.Dependencies) + impl.Logger.Debugw("dependencies found in requirements.yaml file", "appName", pushChartToGitRequest.AppName, "envName", pushChartToGitRequest.EnvName, "dependencies", expectedChartMetaData.Dependencies) // check if chart.yaml file has dependencies chartYamlContent, err := os.ReadFile(chartYamlPath) if err != nil { @@ -500,7 +486,7 @@ func (impl *FullModeDeploymentServiceImpl) shouldMigrateProxyChartDependencies(p latestDependencies := sliceUtil.NewMapFromFuncExec(chartMetadata.Dependencies, func(dependency *chart.Dependency) string { return getUniqueKeyFromDependency(dependency) }) - previousDependencies := sliceUtil.NewMapFromFuncExec(dependencies.Dependencies, func(dependency *chart.Dependency) string { + previousDependencies := sliceUtil.NewMapFromFuncExec(expectedChartMetaData.Dependencies, func(dependency *chart.Dependency) string { return getUniqueKeyFromDependency(dependency) }) for key := range latestDependencies { From ceed2efb98cf3891cda0853ca894aeb4e67d87ea Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Fri, 1 Aug 2025 12:39:00 +0530 Subject: [PATCH 09/10] docs: add developer guide for creating API specs and generating Go beans --- developers-guide/StructGenerator.md | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 developers-guide/StructGenerator.md diff --git a/developers-guide/StructGenerator.md b/developers-guide/StructGenerator.md new file mode 100644 index 0000000000..1893251f31 --- /dev/null +++ b/developers-guide/StructGenerator.md @@ -0,0 +1,77 @@ +# Developer Guide: Creating API Specs and Generating Go Beans + +## 1. Write the OpenAPI Spec + +- Use OpenAPI 3.0+ YAML format. +- Define: + - `info`, `servers`, `tags` + - `paths` for each endpoint, with HTTP methods, parameters, request bodies, and responses. + - `components.schemas` for all request/response objects. +- Use `x-oapi-codegen-extra-tags` for Go struct tags (e.g., validation). +- The default behavior is to generate the required fields as non-pointer types and optional fields as pointer types. + - Use `x-go-type-skip-optional-pointer: false` to ensure fields are generated as pointer type. +- Use `x-go-json-ignore: true` to add `json:"-"` tag to a field, preventing it from being serialized in JSON. +- Use `$ref` to reuse schema definitions. + +**Reference:** +See `specs/bulkEdit/v1beta2/bulk_edit.yaml` for a complete example. +--- + +## 2. Create oapi-codegen Config + +- Create a YAML config file (e.g., `oapi-models-config.yaml`) at the same level as your OpenAPI spec file. +- This file configures the code generation process. +- Set: + - `package`: Go package name for generated code. + - `generate.models`: `true` to generate Go structs. + - `output`: Relative path for the generated file (e.g., `./bean/bean.go`). + - `output-options`: Customize struct naming, skip pruning, etc. + - `exclude-schemas`: Exclude error types if needed. + +**Reference:** +```yaml +# yaml-language-server: ... +package: api +generate: + models: true +output-options: + # to make sure that all types are generated + skip-prune: true + name-normalizer: ToCamelCaseWithDigits + prefer-skip-optional-pointer: true + prefer-skip-optional-pointer-on-container-types: true + exclude-schemas: + - "ErrorResponse" + - "ApiError" +output: {{ // relative path to the generator.go file }} +``` +--- + +## 3. Add go:generate Directive +- In your Go file (e.g., `generator.go`), add a `//go:generate` comment: + ```go + //go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen "--config=../../../../specs/bulkEdit/v1beta2/oapi-models-config.yaml" "../../../../specs/bulkEdit/v1beta2/bulk_edit.yaml" + ``` +- Here `--config` is the relative path (from the `generator.go` file) to your config file, i.e. `oapi-models-config.yaml` file. +- And the last argument is the path to your OpenAPI spec file, i.e. `bulk_edit.yaml`. +--- + +## 4. Generate the Beans +Run: (From the root dir) +```bash + go generate ./pkg/... +``` +> This will generate Go structs at the path specified in your config (e.g., bean/bean.go). +--- + +## 5. Best Practices +Keep OpenAPI specs DRY: use $ref and shared schemas. +Document every field and endpoint. +Use validation tags for all struct fields. +Exclude error response types from bean generation if not needed. +Keep config and spec files versioned and close to your Go code. +--- + +## Summary: +Write your OpenAPI YAML, create a codegen config, add a go:generate directive, and run go generate to produce Go beans at the desired path. +Follow the structure in bulk_edit.yaml and oapi-models-config.yaml for consistency. From ee5790fc7556e5a0f86a05f37276da355e806fa5 Mon Sep 17 00:00:00 2001 From: ayushmaheshwari Date: Fri, 8 Aug 2025 17:18:37 +0530 Subject: [PATCH 10/10] wip --- pkg/pipeline/DeploymentPipelineConfigService.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/pipeline/DeploymentPipelineConfigService.go b/pkg/pipeline/DeploymentPipelineConfigService.go index 8be1ca3dc9..20b81661d5 100644 --- a/pkg/pipeline/DeploymentPipelineConfigService.go +++ b/pkg/pipeline/DeploymentPipelineConfigService.go @@ -1278,6 +1278,7 @@ func (impl *CdPipelineConfigServiceImpl) ValidateLinkFluxAppRequest(ctx context. if helmRelease != nil { chartLocation = helmRelease.Spec.Chart.Spec.Chart + response.FluxReleaseMetadata.Destination.Namespace = helmRelease.GetReleaseNamespace() } if gitRepository != nil { requestedGitUrl = gitRepository.Spec.URL