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/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. diff --git a/internal/util/ChartTemplateService.go b/internal/util/ChartTemplateService.go index b03c86dfa5..317a26d66b 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 } @@ -292,18 +292,24 @@ 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 } 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 +317,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 +382,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..84dfdd3bfd 100644 --- a/pkg/appStore/bean/bean.go +++ b/pkg/appStore/bean/bean.go @@ -298,7 +298,6 @@ func (chart *InstallAppVersionDTO) GetFluxDeploymentConfig() *bean2.DeploymentCo } } -// / type RefChartProxyDir string const ( @@ -336,15 +335,6 @@ type AppNames struct { SuggestedName string `json:"suggestedName,omitempty"` } -type Dependencies struct { - Dependencies []Dependency `json:"dependencies"` -} -type Dependency struct { - Name string `json:"name"` - Version string `json:"version"` - Repository string `json:"repository"` -} - const REFERENCE_TYPE_DEFAULT string = "DEFAULT" const REFERENCE_TYPE_TEMPLATE string = "TEMPLATE" const REFERENCE_TYPE_DEPLOYED string = "DEPLOYED" 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..159739901f 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,19 @@ 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" + "sigs.k8s.io/yaml" "strconv" "strings" ) @@ -57,7 +65,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 +76,35 @@ 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 + 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, dependencyConfig, err := impl.getValuesAndRequirementForGitConfig(installAppVersionRequest, appStoreApplicationVersion) + valuesConfig, chartMetaDataConfig, err := impl.getValuesAndChartMetaDataForGitConfig(installAppVersionRequest, values, 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 +126,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 +137,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, manifest.ChartMetaDataConfig.FileContent) + 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 +210,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 +238,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 +270,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 +336,63 @@ 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 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 + } + 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) { + 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 } - dependency, err := impl.appStoreDeploymentCommonService.GetRequirementsString(appStoreAppVersion) + 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) + chartMetaJsonContent, err := json.Marshal(chartMetaData) + if err != nil { + impl.Logger.Errorw("error in marshalling chartMetaData content", "err", err) + return nil, nil, err + } + 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 } - return valuesConfig, RequirementConfig, nil + return valuesConfig, chartMetaDataConfig, nil } func (impl *FullModeDeploymentServiceImpl) ValidateCustomGitOpsConfig(request validationBean.ValidateGitOpsRepoRequest) (string, bool, error) { @@ -377,3 +426,83 @@ func (impl *FullModeDeploymentServiceImpl) CreateArgoRepoSecretIfNeeded(appStore } return nil } + +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) + return false, err + } + defer impl.chartTemplateService.CleanDir(clonedDir) + gitOpsChartLocation := fmt.Sprintf("%s-%s", pushChartToGitRequest.AppName, pushChartToGitRequest.EnvName) + dir := filepath.Join(clonedDir, gitOpsChartLocation) + 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 + } + 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(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(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", expectedChartMetaData.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{} + 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 + } + 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.NewMapFromFuncExec(chartMetadata.Dependencies, func(dependency *chart.Dependency) string { + return getUniqueKeyFromDependency(dependency) + }) + previousDependencies := sliceUtil.NewMapFromFuncExec(expectedChartMetaData.Dependencies, func(dependency *chart.Dependency) string { + return getUniqueKeyFromDependency(dependency) + }) + 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))) +} 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" 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 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