diff --git a/docs/user-guide/helm.md b/docs/user-guide/helm.md index 3b5a5de0dc262..19094db18a2b3 100644 --- a/docs/user-guide/helm.md +++ b/docs/user-guide/helm.md @@ -236,8 +236,8 @@ source: value: path/to/file.ext ``` -!!! warning "Reference in multiple sources not supported" - Please note that using a multiple sources application will not let you load the file by reference. See [argoproj/argo-cd#13220](https://github.com/argoproj/argo-cd/issues/13220) +!!! warning "Reference in multiple sources not supported prior to ArgoCD 2.12" + Please note that using a multiple sources application will not let you load the file by reference when using ArgoCD versions prior to 2.12 ## Helm Release Name diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 1527c4b372c27..389d256a54fd1 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -474,7 +474,13 @@ func resolveReferencedSources(hasMultipleSources bool, source *v1alpha1.Applicat return repoRefs, nil } - for _, valueFile := range source.ValueFiles { + refFileParams := make([]string, 0) + for _, fileParam := range source.FileParameters { + refFileParams = append(refFileParams, fileParam.Path) + } + refCandidates := append(source.ValueFiles, refFileParams...) + + for _, valueFile := range refCandidates { if strings.HasPrefix(valueFile, "$") { refVar := strings.Split(valueFile, "/")[0] @@ -715,8 +721,14 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, if q.HasMultipleSources { if q.ApplicationSource.Helm != nil { + refFileParams := make([]string, 0) + for _, fileParam := range q.ApplicationSource.Helm.FileParameters { + refFileParams = append(refFileParams, fileParam.Path) + } + refCandidates := append(q.ApplicationSource.Helm.ValueFiles, refFileParams...) + // Checkout every one of the referenced sources to the target revision before generating Manifests - for _, valueFile := range q.ApplicationSource.Helm.ValueFiles { + for _, valueFile := range refCandidates { if strings.HasPrefix(valueFile, "$") { refVar := strings.Split(valueFile, "/")[0] @@ -1168,9 +1180,19 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie } } for _, p := range appHelm.FileParameters { - resolvedPath, _, err := pathutil.ResolveValueFilePathOrUrl(appPath, repoRoot, env.Envsubst(p.Path), q.GetValuesFileSchemes()) - if err != nil { - return nil, fmt.Errorf("error resolving helm value file path: %w", err) + var resolvedPath pathutil.ResolvedFilePath + referencedSource := getReferencedSource(p.Path, q.RefSources) + if referencedSource != nil { + // If the $-prefixed path appears to reference another source, do env substituion _after_ resolving the source + resolvedPath, err = getResolvedRefValueFile(p.Path, env, q.GetValuesFileSchemes(), referencedSource.Repo.Repo, gitRepoPaths) + if err != nil { + return nil, fmt.Errorf("error resolving set-file path: %w", err) + } + } else { + resolvedPath, _, err = pathutil.ResolveValueFilePathOrUrl(appPath, repoRoot, env.Envsubst(p.Path), q.GetValuesFileSchemes()) + if err != nil { + return nil, fmt.Errorf("error resolving helm value file path: %w", err) + } } templateOpts.SetFile[p.Name] = resolvedPath } diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go index f99ce611777c2..1ef028d173cfc 100644 --- a/reposerver/repository/repository_test.go +++ b/reposerver/repository/repository_test.go @@ -2208,6 +2208,47 @@ func TestGenerateManifestWithAnnotatedTagsAndMultiSourceApp(t *testing.T) { } } +func TestGenerateMultiSourceHelmWithFileParameter(t *testing.T) { + + expectedFileContent, err := os.ReadFile("../../util/helm/testdata/external/external-secret.txt") + assert.NoError(t, err) + + service := newService(t, "../../util/helm/testdata") + + refSources := map[string]*argoappv1.RefTarget{} + + refSources["$global"] = &argoappv1.RefTarget{ + TargetRevision: "HEAD", + } + + manifestRequest := &apiclient.ManifestRequest{ + Repo: &argoappv1.Repository{}, + ApplicationSource: &argoappv1.ApplicationSource{ + Ref: "$global", + Path: "./redis", + TargetRevision: "HEAD", + Helm: &argoappv1.ApplicationSourceHelm{ + ValueFiles: []string{"$global/redis/values-production.yaml"}, + FileParameters: []argoappv1.HelmFileParameter{{ + Name: "passwordContent", + Path: "$global/external/external-secret.txt", + }}, + }, + }, + HasMultipleSources: true, + NoCache: true, + RefSources: refSources, + } + + res, err := service.GenerateManifest(context.Background(), manifestRequest) + if err != nil { + t.Errorf("unexpected %s", err) + } + + assert.NoError(t, err) + assert.Contains(t, res.Manifests[0], expectedFileContent, "Value should be provided via file parameters") +} + func TestFindResources(t *testing.T) { testCases := []struct { name string